package net.wicp.tams.duckula.ops.pages.rtdw;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.util.TextStreamResponse;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.google.common.base.Predicate;

import common.kubernetes.apiserver.KubeClient;
import common.kubernetes.constant.CrdVesion;
import lombok.extern.slf4j.Slf4j;
import net.wicp.tams.app.duckula.controller.bean.models.RtdwFlinkbaseimage;
import net.wicp.tams.app.duckula.controller.bean.models.RtdwFlinktask;
import net.wicp.tams.app.duckula.controller.dao.RtdwFlinkbaseimageMapper;
import net.wicp.tams.app.duckula.controller.dao.RtdwFlinktaskMapper;
import net.wicp.tams.app.duckula.controller.service.K8sService;
import net.wicp.tams.common.Result;
import net.wicp.tams.common.apiext.CollectionUtil;
import net.wicp.tams.common.apiext.FreemarkUtil;
import net.wicp.tams.common.apiext.IOUtil;
import net.wicp.tams.common.apiext.StringUtil;
import net.wicp.tams.common.exception.ProjectExceptionRuntime;
import net.wicp.tams.component.tools.TapestryAssist;
import net.wicp.tams.duckula.ops.pages.ParentPageBean;

@Slf4j
public class FlinkTask extends ParentPageBean<RtdwFlinktask> {

	// 上传到文件的子目录
	@Override
	protected String getUploadRelaPath() {
		return "flinkjar";
	}

	@Inject
	private RtdwFlinktaskMapper rtdwFlinktaskMapper;

	@Inject
	private RtdwFlinkbaseimageMapper rtdwFlinkbaseimageMapper;

	@Override
	public void doSave(RtdwFlinktask t, boolean isInsert) {
		if (isInsert) {
			// t.setImageRep("registry.cn-hangzhou.aliyuncs.com/linkedcare/bigdata");
			this.rtdwFlinktaskMapper.insert(t);
		} else {
			this.rtdwFlinktaskMapper.updateByPrimaryKeySelective(t);
		}
	}

	@Override
	public void doDel(String id) {
		this.rtdwFlinktaskMapper.deleteById(id);
	}

	@Override
	public BaseMapper<RtdwFlinktask> getBaseMapper() {
		return this.rtdwFlinktaskMapper;
	}

	@Override
	public void packageQuery(RtdwFlinktask t, QueryWrapper<RtdwFlinktask> queryWrapper) {
		// TODO Auto-generated method stub

	}

	public TextStreamResponse onSubmitTask() {
		final RtdwFlinktask t = TapestryAssist.getBeanFromPage(getTClass(), requestGlobals);
		try {
			Map<String, Object> deployFlinkApplication = deployFlinkApplication(t);
			System.out.println("deployFlinkApplication=" + deployFlinkApplication);
			return TapestryAssist.getTextStreamResponse(Result.getError(""));
		} catch (IOException e) {
			log.error("布署失败", e);
			return TapestryAssist.getTextStreamResponse(Result.getError("cr deploy error:" + e.getMessage()));
		} catch (ProjectExceptionRuntime e) {
			return TapestryAssist.getTextStreamResponse(new Result(e.getExcept()));
		}

	}

	Pair<Double, Integer> baseHost = Pair.of(4.0, 8096);// 一个标准的task是4核8G
	Pair<Double, Integer> singleSlot = Pair.of(1.0, 2048);// 一个slot占用1C2U,要不要留一些给操作系统？后面再说

	private Map<String, Object> deployFlinkApplication(RtdwFlinktask rtdwFlinktask) throws IOException {
		RtdwFlinkbaseimage rtdwFlinkbaseimage = rtdwFlinkbaseimageMapper.selectByPrimaryKey(rtdwFlinktask.getBaseImg());
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("namespace", rtdwFlinktask.getNamespace());
		params.put("name", rtdwFlinktask.getName());
		params.put("imageTag", rtdwFlinkbaseimage.getImageTag());
		params.put("userJarPath", rtdwFlinktask.getUserJarPath());
		Integer slots = rtdwFlinktask.getSlot();
		int taskNum = slots / 4 + 1;
		int hasSlots = slots % 4;
		if (taskNum > 1) {
			params.put("cpu", baseHost.getLeft());
			params.put("mem", baseHost.getRight());
		} else {
			params.put("cpu", singleSlot.getLeft() * hasSlots);
			params.put("mem", singleSlot.getRight() * hasSlots);
		}

		List<String> configs = Arrays.asList(rtdwFlinktask.getFlinkConfig().split("\n"));
		List<String> allConfig = new ArrayList<String>();
		allConfig.addAll(configs);// 直接使用configs做为allConfig会报错，configs不能添加元素
		CollectionUtils.filter(allConfig, new org.apache.commons.collections.Predicate() {
			@Override
			public boolean evaluate(Object arg0) {
				String ele = StringUtil.trimSpace((String) arg0);
				return StringUtil.isNotNull(ele) && !ele.startsWith("taskmanager.numberOfTaskSlots:")
						&& !ele.startsWith("kubernetes.jobmanager.service-account:");
			}
		});
		allConfig.add(String.format("taskmanager.numberOfTaskSlots: %s", taskNum > 1 ? 4 : hasSlots));
		allConfig.add("kubernetes.jobmanager.service-account: flink-native-k8s-operator");
		String configstr = CollectionUtil.listJoin(allConfig, "\n    ");// 后面带4个空格
		params.put("flinkConfig", "    "+configstr);// 前面带4个空格
		String context = IOUtil.slurp(IOUtil.fileToInputStream("/deploy/k8s/cr.yaml", K8sService.class));
		String result = FreemarkUtil.getInst().doProcessByTemp(context, params);
		InputStream is = new ByteArrayInputStream(result.getBytes());
		Map<String, Object> map = KubeClient.createCusObject(CrdVesion.flink, rtdwFlinktask.getNamespace(), is);
		return map;
	}

}
