package org.jeecg.module.custom.ocr.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.module.custom.ocr.api.PrevailCloudApi;
import org.jeecg.module.custom.ocr.api.entity.LivePhoto;
import org.jeecg.module.custom.ocr.api.entity.PictureSourceAllPullMsg;
import org.jeecg.module.custom.ocr.api.thread.PullAllPictureSourceThread;
import org.jeecg.module.custom.ocr.common.entity.RequestData;
import org.jeecg.module.custom.ocr.config.ApiConfig;
import org.jeecg.module.custom.ocr.controller.dto.*;
import org.jeecg.module.custom.ocr.controller.dto.enc.AddTaskEncRequest;
import org.jeecg.module.custom.ocr.controller.dto.enc.DeleteEncTaskRequest;
import org.jeecg.module.custom.ocr.controller.dto.enc.DuplicateTaskEncRequest;
import org.jeecg.module.custom.ocr.service.DuplicateTaskService;
import org.jeecg.module.custom.ocr.service.TaskService;
import org.jeecg.module.custom.ocr.utils.ApiHelper;
import org.jeecg.module.custom.ocr.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.*;


@Api(tags = "ocr_无量云拉取")
@Slf4j
@RestController
@RequestMapping("/api/prevailCloud")
public class PrevailCloudApiController {

    @Resource
    private ApiConfig apiConfig;

    @Autowired
    private PrevailCloudApi prevailCloudApi;

    @Autowired
    private TaskService taskService;

    @Autowired
    private DuplicateTaskService duplicateTaskService;

    @Value("${accessCode}")
    private String accessCode;

    /**
     * 用于执行全量拉取的定长线程池
     */
    private ExecutorService pictureSourceAllPool = new ThreadPoolExecutor(
            1,
            1,
            3,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardOldestPolicy());


    /**
     * 全量拉取，存储执行数据静态对象。
     */
    private static PictureSourceAllPullMsg pictureSourceAllPullMsg = new PictureSourceAllPullMsg();

    /**
     * 拉取无量云全量任务数据，根据业务主体
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "全量拉取", notes = "全量拉取")
    @GetMapping("pullPictureAllByAccountNo")
    public String pullPictureAllByAccountNo(HttpServletRequest request) {

        //检查是否已有全量拉取在执行
        if (pictureSourceAllPullMsg.isLock()) {
            return pictureSourceAllPullMsg.getMsg();
        }

        //1.定义参数
        String beginStr = request.getParameter("beginStr");
        if (StringUtils.isBlank(beginStr)) {
            return "开始时间不能为空";
        }
        String endStr = request.getParameter("endStr");
        if (StringUtils.isBlank(endStr)) {
            return "结束时间不能为空";
        }
        String tenantNoStr = request.getParameter("tenantNo");
        if (StringUtils.isBlank(tenantNoStr)) {
            return "租户不能为空";
        }
        String accountNoStr = request.getParameter("accountNo");
        if (StringUtils.isBlank(accountNoStr)) {
            return "业务主体不能为空";
        }
        Long tenantNo = Long.parseLong(tenantNoStr);
        Long accountNo = Long.parseLong(accountNoStr);


        //2.格式化参数
        DateTime startDate = DateUtil.parse(beginStr + " 00:00:00", "yyyy-MM-dd HH:mm:ss");
        DateTime endDate = DateUtil.parse(endStr + " 23:59:59", "yyyy-MM-dd HH:mm:ss");

        //3.调用线程
        pictureSourceAllPool.execute(
                new PullAllPictureSourceThread(tenantNo, accountNo, startDate
                        , endDate, pictureSourceAllPullMsg, prevailCloudApi, apiConfig)
        );
        return "执行开始";
    }

    /**
     * 添加任务
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "添加任务", notes = "添加任务")
    @PostMapping("/addTask")
    public void addTask(@RequestBody AddTaskEncRequest request) {
        try {
            RequestData requestData = JSON.parseObject(JSON.toJSONString(request), RequestData.class);
            String decryptRequest = ApiHelper.decryptRequest(accessCode, requestData);
            
            // Create ObjectMapper with FAIL_ON_UNKNOWN_PROPERTIES set to false
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            
            // Parse the decrypted request into TaskDTO list
            List<TaskDTO> taskDTOS = objectMapper.readValue(decryptRequest, 
                objectMapper.getTypeFactory().constructCollectionType(List.class, TaskDTO.class));
            
            AddTaskRequest addTaskRequest = convertToAddTaskRequest(request);
            addTaskRequest.getData().setRecords(taskDTOS);
            taskService.save(addTaskRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除任务
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "删除任务", notes = "删除任务")
    @PostMapping("/deleteTask")
    public void deleteTask(@RequestBody @Validated DeleteEncTaskRequest request) {
        try {
            DeleteTaskRequest deleteTaskRequest = convertToDeleteTaskRequest(request);
            RequestData requestData = JSON.parseObject(JSON.toJSONString(request), RequestData.class);
            String decryptRequest = ApiHelper.decryptRequest(accessCode, requestData);
            DeleteTaskData deleteTaskData = JSON.parseObject(decryptRequest, DeleteTaskData.class);
            deleteTaskRequest.setData(deleteTaskData);

            taskService.deleteTasks(deleteTaskData.getTaskNos());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 查重
     *
     * @param request
     * @return
     */
    @ApiOperation(value = "查重", notes = "查重")
    @PostMapping("/checkDuplicate")
    public void checkDuplicate(@RequestBody @Validated DuplicateTaskEncRequest request) {
        try {
            DuplicateTaskRequest duplicateTaskRequest = convertToDuplicateTaskRequest(request);
            RequestData requestData = JSON.parseObject(JSON.toJSONString(request), RequestData.class);
            String decryptRequest = ApiHelper.decryptRequest(accessCode, requestData);
            DuplicateTaskData duplicateTaskData = JSON.parseObject(decryptRequest, DuplicateTaskData.class);

            duplicateTaskRequest.setData(duplicateTaskData);
            duplicateTaskService.save(duplicateTaskRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static AddTaskRequest convertToAddTaskRequest(AddTaskEncRequest encRequest) {
        AddTaskRequest request = new AddTaskRequest();
        request.setTenantCode(encRequest.getTenantCode());
        request.setAccessKey(encRequest.getAccessKey());
        request.setTimestamp(encRequest.getTimestamp());
        request.setSignature(encRequest.getSignature());
        request.setData(new AddTaskData());
        return request;
    }

    private static DuplicateTaskRequest convertToDuplicateTaskRequest(DuplicateTaskEncRequest encRequest) {
        DuplicateTaskRequest request = new DuplicateTaskRequest();
        request.setTenantCode(encRequest.getTenantCode());
        request.setAccessKey(encRequest.getAccessKey());
        request.setTimestamp(encRequest.getTimestamp());
        request.setSignature(encRequest.getSignature());
        request.setData(new DuplicateTaskData());
        return request;
    }

    private static DeleteTaskRequest convertToDeleteTaskRequest(DeleteEncTaskRequest encRequest) {
        DeleteTaskRequest request = new DeleteTaskRequest();
        request.setTenantCode(encRequest.getTenantCode());
        request.setAccessKey(encRequest.getAccessKey());
        request.setTimestamp(encRequest.getTimestamp());
        request.setSignature(encRequest.getSignature());
        return request;
    }
}
