package com.dayou.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dayou.common.BaseEntity;
import com.dayou.configuration.DfsConfig;
import com.dayou.dto.*;
import com.dayou.entity.*;
import com.dayou.enums.MainBusinessEnum;
import com.dayou.enums.ProductionEnum;
import com.dayou.enums.workflow.WorkflowNodeEnum;
import com.dayou.exception.ErrorCode;
import com.dayou.mapper.*;
import com.dayou.service.*;
import com.dayou.service.workflow.IWorkFlowNodeInstanceService;
import com.dayou.service.workflow.IWorkFlowService;
import com.dayou.service.workflow.IWorkTaskRecordService;
import com.dayou.utils.FileUploadUtils;
import com.dayou.utils.PersonalUtils;
import com.dayou.utils.QRCodeUtil;
import com.dayou.vo.ProdValidateVO;
import com.google.zxing.WriterException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.*;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static com.dayou.common.Constants.PNG;
import static com.dayou.common.Constants.PROD_VALIDATE_URI;
import static com.dayou.enums.MainBusinessEnum.*;
import static com.dayou.enums.ProductionEnum.*;
import static com.dayou.enums.workflow.NodeLogEnum.PASS;
import static com.dayou.enums.workflow.WorkflowNodeEnum.*;

/**
 * 类说明：
 *
 * @author: wucl
 * @since: 2024/4/1
 * created with IntelliJ IDEA.
 */
@Slf4j
@Service
public class BusinessProductionServiceImpl implements IBusinessProductionService, ResourceLoaderAware {

    private ResourceLoader resourceLoader;

    @Autowired
    private PersonalTargetMapper personalTargetMapper;

    @Autowired
    private MajorProductionMapper majorProductionMapper;

    @Autowired
    private DfsConfig dfsConfig;
    @Autowired
    private IMajorProductionService majorProductionService;

    @Autowired
    private WorkFlowNodeInstanceMapper workFlowNodeInstanceMapper;

    @Autowired
    private IPersonalProductionService personalProductionService;

    @Autowired
    private IAssetsProductionService assetsProductionService;

    @Autowired
    private IWorkFlowService workFlowService;

    @Autowired
    private IWorkTaskRecordService workTaskRecordService;

    @Autowired
    private IMajorService majorService;
    @Autowired
    private ProductionFundMapper productionFundMapper;
    @Autowired
    private PersonalMapper personalMapper;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public Boolean addPublicStamp(String filePath) {
        try {
            if (StrUtil.isNotBlank(filePath)){
                //filePath 为相对路径，这里需要加上/opt
                filePath = "/opt" + filePath;
                InputStream inputStream = new FileInputStream(filePath);
                Resource resource = resourceLoader.getResource("classpath:static/image/stamp.png");
                PersonalUtils.addPublicStamp(inputStream,resource,filePath);
                inputStream.close();
                return Boolean.TRUE;
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Boolean.FALSE;
    }

    @Override
    public ProdValidateVO validateProd(String businessType, Long businessId) {
        ProdValidateVO prodValidateVO = null;
        if (MainBusinessEnum.PERSONAL_BUSINESS.name().equals(businessType)){
            prodValidateVO = personalTargetMapper.validateProd(businessId);
            if (StrUtil.isNotBlank(prodValidateVO.getBailorA()) && StrUtil.isNotBlank(prodValidateVO.getBailorB())){
                prodValidateVO.setBailor(prodValidateVO.getBailorA()+"、"+prodValidateVO.getBailorB());
            }else if (StrUtil.isNotBlank(prodValidateVO.getBailorA()) && StrUtil.isBlank(prodValidateVO.getBailorB())){
                prodValidateVO.setBailor(prodValidateVO.getBailorA());
            }else {
                prodValidateVO.setBailor(prodValidateVO.getBailorB());
            }
        }
        if (MainBusinessEnum.MAJOR_BUSINESS.name().equals(businessType)){
            prodValidateVO = majorProductionMapper.validateProd(businessId);
        }
        return prodValidateVO;
    }

    @Override
    public String doCreateValidateCode(MainBusinessEnum businessEnum, Long businessId,String reportNo) {
        try {
            String domainRoot = dfsConfig.getDomainRoot();
            String validateUrl = new StringBuffer(domainRoot).append(PROD_VALIDATE_URI).append("?").append("businessType=")
                    .append(businessEnum.name()).append("&").append("targetId=").append(businessId).toString();
            String baseDir = dfsConfig.getPath()+dfsConfig.getCode();
            String dateIndexFileName = FileUploadUtils.createDateIndexFileName(reportNo+"_validate" + PNG);
            File absoluteFile = FileUploadUtils.getAbsoluteFile(baseDir, dateIndexFileName);
            QRCodeUtil.write(validateUrl,200,absoluteFile);
            return dfsConfig.getDomain() + dfsConfig.getCode() + dateIndexFileName;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (WriterException e) {
            throw new RuntimeException(e);
        }
    }


//    public static void main(String[] args) throws IOException, WriterException {
//        String validateUrl = new StringBuffer("http://mbs.scdayou.com/admin").append(PROD_VALIDATE_URI).append("?").append("businessType=")
//                .append(MAJOR_BUSINESS.name()).append("&").append("targetId=").append(9888).toString();
//        String baseDir = "/Users/wuwei/opt/dfs/code";
//        String dateIndexFileName = FileUploadUtils.createDateIndexFileName("川友房函2025010487-2号_validate" + PNG);
//        File absoluteFile = FileUploadUtils.getAbsoluteFile(baseDir, dateIndexFileName);
//        QRCodeUtil.write(validateUrl,200,absoluteFile);
//
//    }

//    public static void main(String[] args) {
//        try {
//            String baseDir = "/Users/wuwei/opt/dfs/code";
//            String dateIndexFileName = FileUploadUtils.createDateIndexFileName("川友房函2025010487-2号" + PNG);
//            File absoluteFile = FileUploadUtils.getAbsoluteFile(baseDir, dateIndexFileName);
//            QRCodeUtil.write("川友房函2025010487-2号",200,absoluteFile);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        } catch (WriterException e) {
//            throw new RuntimeException(e);
//        }
//    }

    @Override
    public String doCreateNormalCode(String production,String reportNo) {
        try {
            String baseDir = dfsConfig.getPath()+dfsConfig.getCode();
            String dateIndexFileName = FileUploadUtils.createDateIndexFileName(reportNo + PNG);
            File absoluteFile = FileUploadUtils.getAbsoluteFile(baseDir, dateIndexFileName);
            QRCodeUtil.write(reportNo,200,absoluteFile);
            return dfsConfig.getDomain() + dfsConfig.getCode() + dateIndexFileName;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (WriterException e) {
            throw new RuntimeException(e);
        }
    }

    @Transactional
    @Override
    public Boolean inOutWareHouse(String productionNo) {
        if (StrUtil.isNotBlank(productionNo)){

            Map<String,Object> nodeMap = workFlowNodeInstanceMapper.getInOutInstanceNode(productionNo);
            if (CollectionUtil.isEmpty(nodeMap)){
                ErrorCode.throwBusinessException(ErrorCode.CUSTOM_ERROR,"该产品目前还不能进行出入库操作。");
            }
            MainBusinessEnum businessType = MainBusinessEnum.valueOf((String) nodeMap.get("businessType"));
            Long businessId = (Long) nodeMap.get("businessId");
            Long recodeId = (Long) nodeMap.get("id");
            String code = (String) nodeMap.get("code");

            //完成出库业务操作
            Boolean doRet = doInOutWareHouse(businessType, businessId, recodeId, productionNo,code);

            if (doRet){
                //提交工作流节点
                WorkNodeCommit workNodeCommit = new WorkNodeCommit();
                workNodeCommit.setState(PASS);
                workNodeCommit.setIfCheckTask(true);
                workNodeCommit.setComments(code.contains("IN")?"入库":"出库");
                workNodeCommit.setInstanceNodeId((Long) nodeMap.get("instanceId"));
                workNodeCommit.setBusinessSubId((String) nodeMap.get("businessSubId"));
                workNodeCommit.setBusinessMinId((String) nodeMap.get("businessMinId"));
                if (MainBusinessEnum.MAJOR_BUSINESS.equals(businessType)){
                    Major feedback = majorService.getOne(new LambdaQueryWrapper<Major>().eq(BaseEntity::getId, businessId).select(Major::getFeedbackInfo));
                    List<ReportProductionFeedbackDTO> feedbacks = JSON.parseArray(feedback.getFeedbackInfo(), ReportProductionFeedbackDTO.class);
                    List<ProductionEnum> productions = feedbacks.get(feedbacks.size() - 1).getProduction();
                    workNodeCommit.setProduction(productions);
                }
                if (MainBusinessEnum.ASSET_BUSINESS.equals(businessType) && StrUtil.isNotBlank(workNodeCommit.getBusinessMinId())){
                    ProductionFund productionFund = productionFundMapper.selectOne(new LambdaQueryWrapper<ProductionFund>().select(BaseEntity::getId,ProductionFund::getRealAmount)
                            .eq(ProductionFund::getBusinessType, ASSET_BUSINESS.name()).eq(ProductionFund::getBusinessId, businessId)
                            .eq(ProductionFund::getProductionNo, workNodeCommit.getBusinessMinId()).eq(BaseEntity::getDeleted, Boolean.FALSE));
                    workNodeCommit.setIfProductionFund(productionFund.getRealAmount()!=null);
                }
                if (MainBusinessEnum.PERSONAL_BUSINESS.equals(businessType)){
                    PersonalTarget personalTarget = personalTargetMapper.selectOne(new LambdaQueryWrapper<PersonalTarget>().eq(PersonalTarget::getPersonalId, businessId)
                            .select(PersonalTarget::getFeedback).eq(BaseEntity::getDeleted, Boolean.FALSE));
                    workNodeCommit.setProduction(JSON.parseArray(personalTarget.getFeedback(),ProductionEnum.class));
                    Personal personal = personalMapper.selectOne(new LambdaQueryWrapper<Personal>().select(Personal::getClienteleId).eq(BaseEntity::getId, businessId).eq(BaseEntity::getDeleted, Boolean.FALSE));
                    if (personal != null){
                        workNodeCommit.setCcId(personal.getClienteleId());
                    }
                }
                return workFlowService.commit(workNodeCommit);
            }

        }
        return Boolean.FALSE;
    }


    private Boolean doInOutWareHouse(MainBusinessEnum businessEnum,Long businessId,Long recordId,String productionNo,String code) {

        Boolean doWareHouseRet = Boolean.FALSE;
        switch (businessEnum){
            case PERSONAL_BUSINESS:
                TaskRecordDTO<PersonalProduction> taskRecord = new TaskRecordDTO<>();
                taskRecord.setRecordId(recordId);
                PersonalTarget personalTarget = personalTargetMapper.selectOne(new LambdaQueryWrapper<PersonalTarget>()
                        .eq(PersonalTarget::getPersonalId, businessId)
                        .select(BaseEntity::getId));
                Long targetId = personalTarget.getId();
                PersonalProduction production = new PersonalProduction();
                production.setTargetId(targetId);
                if (STATEMENT_IN.name().equals(code)){
                    production.setProduction(STATEMENT.name());
                    taskRecord.setTaskData(production);
                    doWareHouseRet = personalProductionService.repertoryIn(taskRecord);
                }else if (STATEMENT_OUT.name().equals(code)){
                    production.setProduction(STATEMENT.name());
                    taskRecord.setTaskData(production);
                    doWareHouseRet = personalProductionService.repertoryOut(taskRecord);
                }else if (REPORT_IN.name().equals(code)){
                    production.setProduction(REPORT.name());
                    taskRecord.setTaskData(production);
                    doWareHouseRet = personalProductionService.repertoryIn(taskRecord);
                }else if (REPORT_OUT.name().equals(code)){
                    production.setProduction(REPORT.name());
                    taskRecord.setTaskData(production);
                    doWareHouseRet = personalProductionService.repertoryOut(taskRecord);
                }else if (LETTER_IN.name().equals(code)){
                    production.setProduction(LETTER.name());
                    taskRecord.setTaskData(production);
                    doWareHouseRet = personalProductionService.repertoryIn(taskRecord);
                }else if (LETTER_OUT.name().equals(code)){
                    production.setProduction(LETTER.name());
                    taskRecord.setTaskData(production);
                    doWareHouseRet = personalProductionService.repertoryOut(taskRecord);
                }
                break;
            case MAJOR_BUSINESS:
                TaskRecordDTO<WareHouseDTO> taskRecordDTO = new TaskRecordDTO<>();
                taskRecordDTO.setRecordId(recordId);
                MajorProduction mp = majorProductionService.getOne(new LambdaQueryWrapper<MajorProduction>()
                        .select(BaseEntity::getId,MajorProduction::getProduction,MajorProduction::getRepertoryState)
                        .eq(MajorProduction::getMajorId, businessId)
                        .eq(MajorProduction::getReportNo, productionNo));
                Long productionId = mp.getId();
                String productionType = mp.getProduction();
                Boolean state = mp.getRepertoryState()==null?Boolean.FALSE:Boolean.TRUE;
                WareHouseDTO wareHouseDTO = WareHouseDTO.builder()
                        .productionId(productionId)
                        .productionType(productionType)
                        .repertoryState(Boolean.FALSE)
                        .repertoryState(state)
                        .reportNo(productionNo).build();
                taskRecordDTO.setTaskData(wareHouseDTO);
                doWareHouseRet = majorProductionService.warehouse(taskRecordDTO);
                break;
            case ASSET_BUSINESS:
                AssetsProduction ap = assetsProductionService.getOne(new LambdaQueryWrapper<AssetsProduction>()
                        .select(BaseEntity::getId, AssetsProduction::getProductionType, AssetsProduction::getRepertoryState)
                        .eq(AssetsProduction::getBusinessId, businessId)
                        .eq(AssetsProduction::getProductionNo, productionNo));
                Long id = ap.getId();
                String pt = ap.getProductionType();
                Boolean status = ap.getRepertoryState()==null?Boolean.FALSE:Boolean.TRUE;
                AssetsProWareHouseDTO assetsProWareHouseDTO = new AssetsProWareHouseDTO();
                assetsProWareHouseDTO.setBusinessId(businessId);
                assetsProWareHouseDTO.setProductionId(id);
                assetsProWareHouseDTO.setProductionType(pt);
                assetsProWareHouseDTO.setRepertoryState(status);
                assetsProWareHouseDTO.setProductionNo(productionNo);
                doWareHouseRet = assetsProductionService.assetsProRepertory(assetsProWareHouseDTO);
                break;
        }
        if (doWareHouseRet){
            //完成任务
            return workTaskRecordService.update(new LambdaUpdateWrapper<WorkTaskRecord>().set(WorkTaskRecord::getFinished, Boolean.TRUE)
                    .set(WorkTaskRecord::getFinishTime, LocalDateTime.now()).eq(BaseEntity::getId, recordId));
        }
        return doWareHouseRet;

    }
}
