package com.taais.biz.service.impl;

import java.lang.reflect.Type;
import java.util.*;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.taais.biz.constant.BizConstant;
import com.taais.biz.domain.*;
import com.taais.biz.domain.bo.AlgorithmModelBo;
import com.taais.biz.domain.bo.TargetIdentificationSubtaskDetailsBo;
import com.taais.biz.domain.dto.AlgorithmConfigParamDto;
import com.taais.biz.domain.dto.AlgorithmRequestDto;
import com.taais.biz.domain.vo.AlgorithmModelVo;
import com.taais.biz.domain.vo.AlgorithmTaskConfigurationVo;
import com.taais.biz.domain.vo.TargetIdentificationSubtaskDetailsVo;
import com.taais.common.core.constant.Constants;
import com.taais.common.core.utils.MapstructUtils;
import com.taais.common.core.utils.StringUtils;
import com.taais.common.log.annotation.Log;
import com.taais.common.orm.core.page.PageQuery;
import com.taais.common.core.core.page.PageResult;
import com.taais.common.orm.core.service.impl.BaseServiceImpl;
import com.taais.system.domain.vo.SysOssVo;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.taais.biz.mapper.TargetIdentificationSubtaskMapper;
import com.taais.biz.domain.bo.TargetIdentificationSubtaskBo;
import com.taais.biz.domain.vo.TargetIdentificationSubtaskVo;
import com.taais.biz.service.ITargetIdentificationSubtaskService;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import static com.taais.biz.domain.table.TargetIdentificationSubtaskTableDef.TARGET_IDENTIFICATION_SUBTASK;

/**
 * 目标识别子任务Service业务层处理
 *
 * @author Allen
 * 2024-08-17
 */
@Service
@Slf4j
public class TargetIdentificationSubtaskServiceImpl extends BaseServiceImpl<TargetIdentificationSubtaskMapper, TargetIdentificationSubtask> implements ITargetIdentificationSubtaskService {
    @Resource
    private TargetIdentificationSubtaskMapper targetIdentificationSubtaskMapper;

    @Resource
    private TargetIdentificationSubtaskDetailsServiceImpl detailsService;

    @Resource
    private AlgorithmTaskConfigurationServiceImpl algorithmTaskConfigurationService;

    @Resource
    AlgorithmModelServiceImpl algorithmModelService;

    @Override
    public QueryWrapper query() {
        return super.query().from(TARGET_IDENTIFICATION_SUBTASK);
    }

    private QueryWrapper buildQueryWrapper(TargetIdentificationSubtaskBo targetIdentificationSubtaskBo) {
        QueryWrapper queryWrapper = super.buildBaseQueryWrapper();
        queryWrapper.and(TARGET_IDENTIFICATION_SUBTASK.NAME.like
        (targetIdentificationSubtaskBo.getName()));
        System.out.println("definition is: " + TARGET_IDENTIFICATION_SUBTASK);
        queryWrapper.and(TARGET_IDENTIFICATION_SUBTASK.TASK_ID.eq
            (targetIdentificationSubtaskBo.getTaskId()));
        queryWrapper.and(TARGET_IDENTIFICATION_SUBTASK.STATUS.eq
        (targetIdentificationSubtaskBo.getStatus()));
        queryWrapper.and(TARGET_IDENTIFICATION_SUBTASK.REMARKS.eq
        (targetIdentificationSubtaskBo.getRemarks()));
        return queryWrapper;
    }

    /**
     * 查询目标识别子任务
     *
     * @param id 目标识别子任务主键
     * @return 目标识别子任务
     */
    @Override
    public TargetIdentificationSubtaskVo selectById(Long id) {
            return this.getOneAs(query().where(TARGET_IDENTIFICATION_SUBTASK.ID.eq(id)), TargetIdentificationSubtaskVo.class);

    }

    /**
     * 查询目标识别子任务列表
     *
     * @param targetIdentificationSubtaskBo 目标识别子任务Bo
     * @return 目标识别子任务集合
     */
    @Override
    public List<TargetIdentificationSubtaskVo> selectList(TargetIdentificationSubtaskBo targetIdentificationSubtaskBo) {
        QueryWrapper queryWrapper = buildQueryWrapper(targetIdentificationSubtaskBo);
            return this.listAs(queryWrapper, TargetIdentificationSubtaskVo.class);
    }

    /**
     * 分页查询目标识别子任务列表
     *
     * @param targetIdentificationSubtaskBo 目标识别子任务Bo
     * @return 分页目标识别子任务集合
     */
    @Override
    public PageResult<TargetIdentificationSubtaskVo> selectPage(TargetIdentificationSubtaskBo targetIdentificationSubtaskBo) {
        QueryWrapper queryWrapper = buildQueryWrapper(targetIdentificationSubtaskBo);
            Page<TargetIdentificationSubtaskVo> page = this.pageAs(PageQuery.build(), queryWrapper, TargetIdentificationSubtaskVo.class);
        return PageResult.build(page);
    }

    /**
     * 新增目标识别子任务
     *
     * @param targetIdentificationSubtaskBo 目标识别子任务Bo
     * @return 结果:true 操作成功，false 操作失败
     */
    @Override
    public boolean insert(TargetIdentificationSubtaskBo targetIdentificationSubtaskBo) {
    TargetIdentificationSubtask targetIdentificationSubtask =MapstructUtils.convert(targetIdentificationSubtaskBo, TargetIdentificationSubtask. class);

        return this.save(targetIdentificationSubtask);//使用全局配置的雪花算法主键生成器生成ID值
    }

    @Override
    public TargetIdentificationSubtask insertSubtask(TargetIdentificationSubtaskBo targetIdentificationSubtaskBo) {
        TargetIdentificationSubtask targetIdentificationSubtask =MapstructUtils.convert(targetIdentificationSubtaskBo, TargetIdentificationSubtask. class);

        this.save(targetIdentificationSubtask);//使用全局配置的雪花算法主键生成器生成ID值

        return targetIdentificationSubtask;
    }

    /**
     * 修改目标识别子任务
     *
     * @param targetIdentificationSubtaskBo 目标识别子任务Bo
     * @return 结果:true 更新成功，false 更新失败
     */
    @Override
    public boolean update(TargetIdentificationSubtaskBo targetIdentificationSubtaskBo) {
        TargetIdentificationSubtask targetIdentificationSubtask =MapstructUtils.convert(targetIdentificationSubtaskBo, TargetIdentificationSubtask. class);
        if (ObjectUtil.isNotNull(targetIdentificationSubtask) && ObjectUtil.isNotNull(targetIdentificationSubtask.getId())){
            boolean updated = this.updateById(targetIdentificationSubtask);
                return updated;
        }
        return false;
    }

    /**
     * 批量删除目标识别子任务
     *
     * @param ids 需要删除的目标识别子任务主键集合
     * @return 结果:true 删除成功，false 删除失败
     */
    @Transactional
    @Override
    public boolean deleteByIds(Long[] ids) {
        return this.removeByIds(Arrays.asList(ids));
    }

    @Override
    public void taskRun(TargetIdentificationTask task) {
        TargetIdentificationSubtask targetIdentificationSubtask = targetIdentificationSubtaskMapper.getAvailableSubtask(task.getId());
        doProcess(targetIdentificationSubtask);
    }

    public void executeOneTask(Long taskId) {
        TargetIdentificationSubtaskDetailsBo details = detailsService.getById(taskId);

        log.info("details: {}", details);
        doProcessSubTaskDetail(details);
    }

    private void doProcess(TargetIdentificationSubtask subtask) {
        List<TargetIdentificationSubtaskDetailsBo> detailsList = detailsService.getTargetIdentificationSubtaskDetailsListBySubtaskId(subtask.getId());

        for (TargetIdentificationSubtaskDetailsBo detail : detailsList) {
            doProcessSubTaskDetail(detail);
        }
    }


    /**
     * 执行子任务详情
     * @param detail
     */
    private void doProcessSubTaskDetail(TargetIdentificationSubtaskDetailsBo detail) {
        final String MINI_PREFIX = "/task";
        Long algorithmId = null;
        Long modelId = null;
        String parameters = null;
        String preprocessPath = null;
        String resultPath = null;
        String url = null;

        url = detail.getType();
        parameters = detail.getParameters();
        preprocessPath = detail.getPreprocessPath();
        resultPath = detail.getResultPath();
        AlgorithmRequestDto algorithmRequestDto = new AlgorithmRequestDto();
        algorithmRequestDto.setBizType(BizConstant.TYPE_DATA_BIZ_PROCESS);
        algorithmRequestDto.setBizId(detail.getId());
        algorithmRequestDto.setSourcePath(BizConstant.DOCKER_BASE_PATH + MINI_PREFIX + preprocessPath);
        algorithmRequestDto.setResultPath(BizConstant.DOCKER_BASE_PATH + MINI_PREFIX + resultPath);
        algorithmRequestDto.setLogPath(BizConstant.DOCKER_BASE_PATH + MINI_PREFIX + resultPath + "/log/log.log");
        algorithmRequestDto.setOtherParams(new HashMap<>());

        boolean hasModelProperty = false;
        String _modelId = null;
        try {
            JSONArray jsonArray = JSON.parseArray(parameters);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject object = jsonArray.getJSONObject(i);
                if ("pretrained_model".equals(object.getString("agName"))) {
                    hasModelProperty = true;
                    _modelId = object.getString("modelId");
                }
                String value = object.getString("defaultValue");
                if(NumberUtils.isCreatable(value)){
                    algorithmRequestDto.getOtherParams().put(object.getString("agName"), NumberUtils.createNumber(value));
                } else {
                    algorithmRequestDto.getOtherParams().put(object.getString("agName"), value);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        if (hasModelProperty) {
            AlgorithmModelVo bo = algorithmModelService.selectById(Long.valueOf(_modelId));
            String path = bo.getModelAddress().replace("/profile", BizConstant.DOCKER_BASE_PATH);
            algorithmRequestDto.getOtherParams().put("pretrained", true);
            algorithmRequestDto.getOtherParams().put("pretrained_model", path);
        }

        String taskName = detail.getName();
        if (taskName.contains("训练")) {
            log.info("train");
        } else if (taskName.contains("验证")) {
            String[] urls = url.split(";;;");
            url = urls[0];
            if (urls.length > 1) {
                algorithmRequestDto.getOtherParams().put("weight_path", BizConstant.DOCKER_BASE_PATH + MINI_PREFIX + urls[1] + "/result/weights/best.pt");
            }
        } else if (taskName.contains("测试")) {
            String[] urls = url.split(";;;");
            url = urls[0];
            if (urls.length > 1) {
                algorithmRequestDto.getOtherParams().put("weight_path", BizConstant.DOCKER_BASE_PATH + MINI_PREFIX + urls[1] + "/result/weights/best.pt");
            }
        } else {
            log.error("taskName error: " + taskName);
            return;
        }
        // send http
        log.info("todo request: " + algorithmRequestDto);

        try {
            String res = HttpUtil.post(url, JSONUtil.toJsonStr(algorithmRequestDto));
            log.info("res is: {}", res);
        } catch (Exception e) {
            log.error("http request error: {}", e.getMessage());
            detail.setStatus(BizConstant.TASK_STATUS_FAILED);
            detail.setRemarks("HTTP请求异常: " + (e.getMessage().length() < 200 ? e.getMessage() : e.getMessage().substring(0, 200)));
            detail.setEndTime(new Date());
            detail.setCostSecond(detail.getEndTime().getTime() - detail.getStartTime().getTime());
        } finally {
            detailsService.update(detail);
        }
    }

    public List<TargetIdentificationSubtaskVo> getSubtaskList(Long taskId) {
        return targetIdentificationSubtaskMapper.selectList(taskId);
    }
}
