package org.agt.module.license.service.project;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.agt.framework.common.pojo.PageResult;
import org.agt.framework.common.util.object.BeanUtils;
import org.agt.module.license.controller.admin.license.vo.ImportRespVO;
import org.agt.module.license.controller.admin.project.vo.ProjectImportRespVO;
import org.agt.module.license.controller.admin.project.vo.ProjectListReqVO;
import org.agt.module.license.controller.admin.project.vo.ProjectPageReqVO;
import org.agt.module.license.controller.admin.project.vo.ProjectRespVO;
import org.agt.module.license.controller.admin.project.vo.ProjectSaveReqVO;
import org.agt.module.license.dal.dataobject.customer.CustomerDO;
import org.agt.module.license.dal.dataobject.license.LicenseDO;
import org.agt.module.license.dal.dataobject.project.ProjectDO;
import org.agt.module.license.dal.mysql.comment.CommentMapper;
import org.agt.module.license.dal.mysql.customer.CustomerMapper;
import org.agt.module.license.dal.mysql.license.LicenseHistoryMapper;
import org.agt.module.license.dal.mysql.license.LicenseMapper;
import org.agt.module.license.dal.mysql.project.ProjectMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import static org.agt.framework.common.exception.util.ServiceExceptionUtil.exception;
import static org.agt.module.license.enums.ErrorCodeConstants.PROJECT_CODE_DUPLICATE;
import static org.agt.module.license.enums.ErrorCodeConstants.PROJECT_EXISTS_LICENSE;
import static org.agt.module.license.enums.ErrorCodeConstants.PROJECT_IMPORT_LIST_IS_EMPTY;
import static org.agt.module.license.enums.ErrorCodeConstants.PROJECT_NAME_DUPLICATE;
import static org.agt.module.license.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_CREATE_SUB_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_CREATE_SUCCESS;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_DELETE_SUB_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_DELETE_SUCCESS;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_UPDATE_SUB_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_PROJECT_UPDATE_SUCCESS;

/**
 * 项目 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class ProjectServiceImpl implements ProjectService {

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private CustomerMapper customerMapper;

    @Resource
    private CommentMapper commentMapper;

    @Resource
    private LicenseMapper licenseMapper;

    @Resource
    private LicenseHistoryMapper licenseHistoryMapper;

    @Override
    @LogRecord(type = SYSTEM_PROJECT_TYPE, subType = SYSTEM_PROJECT_CREATE_SUB_TYPE, bizNo = "{{#project.id}}",
            success = SYSTEM_PROJECT_CREATE_SUCCESS)
    public Long createProject(ProjectSaveReqVO createReqVO) {
        // 校验项目名称和编号是否唯一
        validateProjectNameAndCodeUnique(createReqVO.getName(), createReqVO.getCode(), createReqVO.getId());
        // 插入
        ProjectDO project = BeanUtils.toBean(createReqVO, ProjectDO.class);
        projectMapper.insert(project);

        LogRecordContext.putVariable("project", project);
        // 返回
        return project.getId();
    }

    @Override
    @LogRecord(type = SYSTEM_PROJECT_TYPE, subType = SYSTEM_PROJECT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = SYSTEM_PROJECT_UPDATE_SUCCESS)
    public void updateProject(ProjectSaveReqVO updateReqVO) {
        // 校验项目名称和编号是否唯一
        validateProjectNameAndCodeUnique(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId());
        // 校验存在
        ProjectDO project = validateProjectExists(updateReqVO.getId());
        // 更新
        ProjectDO updateObj = BeanUtils.toBean(updateReqVO, ProjectDO.class);
        projectMapper.updateById(updateObj);

        if (updateReqVO.getEndTime() == null) {
            projectMapper.update(Wrappers.<ProjectDO>lambdaUpdate().eq(ProjectDO::getId, updateObj.getId())
                    .set(ProjectDO::getEndTime, updateObj.getEndTime()));
        }

        // 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(project, ProjectSaveReqVO.class));
        LogRecordContext.putVariable("project", project);
    }

    @Override
    @LogRecord(type = SYSTEM_PROJECT_TYPE, subType = SYSTEM_PROJECT_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_PROJECT_DELETE_SUCCESS)
    public void deleteProject(Long id) {
        // 校验存在
        ProjectDO project = validateProjectExists(id);

        List<LicenseDO> licenses = licenseMapper.selectList(Wrappers.<LicenseDO>lambdaQuery().eq(LicenseDO::getProjectId, project.getId()));
        if (CollUtil.isNotEmpty(licenses)) {
            throw exception(PROJECT_EXISTS_LICENSE);
        }
        // 删除
        projectMapper.deleteById(id);
        LogRecordContext.putVariable("project", project);
    }

    private ProjectDO validateProjectExists(Long id) {
        ProjectDO projectDO = projectMapper.selectById(id);
        if (projectDO == null) {
            throw exception(PROJECT_NOT_EXISTS);
        }

        return projectDO;
    }

    private void validateProjectNameAndCodeUnique(String name, String code, Long id) {
        Boolean isNameUnique = validateProjectNameUnique(name, id);
        if (!isNameUnique) {
            throw exception(PROJECT_NAME_DUPLICATE, name);
        }
        Boolean isCodeUnique = validateProjectCodeUnique(code, id);
        if (!isCodeUnique) {
            throw exception(PROJECT_CODE_DUPLICATE, code);
        }
    }

    @Override
    public ProjectDO getProject(Long id) {
        return projectMapper.selectById(id);
    }

    @Override
    public PageResult<ProjectRespVO> getProjectPage(ProjectPageReqVO pageReqVO) {
        if (StrUtil.isNotBlank(pageReqVO.getSortField())) {
            pageReqVO.setSortField(StrUtil.toUnderlineCase(pageReqVO.getSortField()));
        }
        IPage<ProjectRespVO> page = projectMapper.queryPage(new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO);

        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public List<ProjectRespVO> getProjectList(ProjectListReqVO reqVO) {
        return projectMapper.queryList(reqVO);
    }

    @Override
    public Boolean validateProjectNameUnique(String name, Long id) {
        if (StrUtil.isBlank(name)) {
            return true;
        }
        ProjectDO project = projectMapper.selectByName(name);
        if (project == null) {
            return true;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的客户
        if (id == null) {
            return false;
        }
        if (!project.getId().equals(id)) {
            return false;
        }
        return true;
    }

    @Override
    public Boolean validateProjectCodeUnique(String code, Long id) {
        if (StrUtil.isBlank(code)) {
            return true;
        }
        ProjectDO project = projectMapper.selectByCode(code);
        if (project == null) {
            return true;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的客户
        if (id == null) {
            return false;
        }
        if (!project.getId().equals(id)) {
            return false;
        }
        return true;
    }

    @Override
    public Integer selectMaxCode() {
        Integer maxCode = projectMapper.selectMaxCode();
        return maxCode == null || maxCode < 2000 ? 2000 : maxCode;
    }

    @Override
    public ImportRespVO importList(List<ProjectImportRespVO> list, Boolean updateSupport) {
        if (CollUtil.isEmpty(list)) {
            throw exception(PROJECT_IMPORT_LIST_IS_EMPTY);
        }
        ImportRespVO respVO = ImportRespVO.builder().creates(new ArrayList<>())
                .updates(new ArrayList<>()).failures(new LinkedHashMap<>()).build();

        for (ProjectImportRespVO importRespVO : list) {
            String name = importRespVO.getName();
            String serialNo = importRespVO.getSerialNo();

            if (StrUtil.isBlank(name)) {
                respVO.getFailures().put(name, "项目名称不能为空");
                continue;
            }

            if (StrUtil.isBlank(serialNo)) {
                respVO.getFailures().put(name, "SN不能为空");
                continue;
            }

            Long customerId = null;
            String projectCode = "";
            try {
                String customerCode = serialNo.substring(0, 4);
                projectCode = serialNo.substring(4);
                CustomerDO customerDO = customerMapper.selectOne(Wrappers.<CustomerDO>lambdaQuery().eq(CustomerDO::getCode, customerCode));
                customerId = customerDO.getId();
            } catch (Exception e) {
                log.info("导入报错：{}", e.getMessage());
            }
            if (StrUtil.isBlank(projectCode)) {
                respVO.getFailures().put(name, "SN不正确");
                continue;
            }
            if (customerId == null) {
                respVO.getFailures().put(name, "所属客户不存在");
                continue;
            }

            if (importRespVO.getStartTime() == null) {
                respVO.getFailures().put(name, "项目开始时间不能为空");
                continue;
            }
            if (StrUtil.isBlank(importRespVO.getContractCode())) {
                respVO.getFailures().put(name, "合同不能为空");
                continue;
            }
            if (importRespVO.getStatus() == null) {
                respVO.getFailures().put(name, "项目状态不能为空");
                continue;
            }
            if (StrUtil.isBlank(importRespVO.getBusinessOwnerName())) {
                respVO.getFailures().put(name, "业务负责人不能为空");
                continue;
            }
            importRespVO.setBusinessOwner(customerMapper.getUserByName(importRespVO.getBusinessOwnerName()));
            if (StrUtil.isBlank(importRespVO.getTechnicalOwnerAName())) {
                respVO.getFailures().put(name, "技术负责人1不能为空");
                continue;
            }
            importRespVO.setTechnicalOwnerA(customerMapper.getUserByName(importRespVO.getTechnicalOwnerAName()));
            if (importRespVO.getBusinessStatus() == null) {
                respVO.getFailures().put(name, "商务状态不能为空");
                continue;
            }
            if (StrUtil.isBlank(importRespVO.getCustomerOwner())) {
                respVO.getFailures().put(name, "客户对接人不能为空");
                continue;
            }
            if (importRespVO.getEnvInfo() == null) {
                respVO.getFailures().put(name, "环境信息不能为空");
                continue;
            }
            if (importRespVO.getSoftwareVersion() == null) {
                respVO.getFailures().put(name, "软件版本信息不能为空");
                continue;
            }
            if (importRespVO.getOperatingSystem() == null) {
                respVO.getFailures().put(name, "操作系统不能为空");
                continue;
            }
            ProjectDO projectDO = BeanUtils.toBean(importRespVO, ProjectDO.class);
            projectDO.setCode(projectCode);
            projectDO.setCustomerId(customerId);

            ProjectDO project = projectMapper.selectByCode(projectDO.getCode());
            if (project == null) {
                projectMapper.insert(projectDO);
                respVO.getCreates().add(name);
                continue;
            }
            if (!updateSupport) {
                respVO.getFailures().put(name, "项目编号已存在");
                continue;
            }
            projectDO.setId(project.getId());
            projectMapper.updateById(projectDO);
            respVO.getUpdates().add(name);
        }
        return respVO;
    }

    @Override
    public List<ProjectRespVO> getLicenseProjects(ProjectListReqVO reqVO) {
        return projectMapper.getLicenseProjects(reqVO);
    }
}