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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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 org.agt.framework.common.pojo.PageResult;
import org.agt.framework.common.util.object.BeanUtils;
import org.agt.framework.ip.core.utils.AreaUtils;
import org.agt.module.license.controller.admin.customer.vo.CustomerImportRespVO;
import org.agt.module.license.controller.admin.customer.vo.CustomerPageReqVO;
import org.agt.module.license.controller.admin.customer.vo.CustomerRespVO;
import org.agt.module.license.controller.admin.customer.vo.CustomerSaveReqVO;
import org.agt.module.license.controller.admin.customer.vo.DashboardRespVO;
import org.agt.module.license.controller.admin.license.vo.ImportRespVO;
import org.agt.module.license.dal.dataobject.customer.CustomerDO;
import org.agt.module.license.dal.dataobject.project.ProjectDO;
import org.agt.module.license.dal.mysql.customer.CustomerMapper;
import org.agt.module.license.dal.mysql.license.LicenseMapper;
import org.agt.module.license.dal.mysql.project.ProjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
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.CUSTOMER_CODE_DUPLICATE;
import static org.agt.module.license.enums.ErrorCodeConstants.CUSTOMER_EXISTS_PROJECT;
import static org.agt.module.license.enums.ErrorCodeConstants.CUSTOMER_IMPORT_LIST_IS_EMPTY;
import static org.agt.module.license.enums.ErrorCodeConstants.CUSTOMER_NAME_DUPLICATE;
import static org.agt.module.license.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_CREATE_SUB_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_CREATE_SUCCESS;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_DELETE_SUB_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_DELETE_SUCCESS;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_UPDATE_SUB_TYPE;
import static org.agt.module.license.enums.LogRecordConstants.SYSTEM_CUSTOMER_UPDATE_SUCCESS;

/**
 * 客户 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class CustomerServiceImpl implements CustomerService {

    private static final Logger log = LoggerFactory.getLogger(CustomerServiceImpl.class);
    @Resource
    private CustomerMapper customerMapper;

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private LicenseMapper licenseMapper;

    @Override
    public DashboardRespVO dashboard() {
        Long customerCount = customerMapper.selectCount(Wrappers.<CustomerDO>lambdaQuery().notIn(CustomerDO::getName, Arrays.asList("AGT", "BA", "Blue Arcus")));
        DashboardRespVO projectRespVO = customerMapper.getProjectCount();
        Long projectCount = projectRespVO.getProjectCount();
        Long contractCount = projectRespVO.getContractCount();
        DashboardRespVO dashboardRespVO = customerMapper.getLicenseCount();
        dashboardRespVO.setCustomerCount(customerCount);
        dashboardRespVO.setProjectCount(projectCount);
        dashboardRespVO.setContractCount(contractCount);
        dashboardRespVO.setUserCount(customerMapper.selectUserCount());
        if (projectCount == 0) {
            dashboardRespVO.setSigningRate(0L);
        } else {
            dashboardRespVO.setSigningRate(BigDecimal.valueOf(contractCount).multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(projectCount), 0, RoundingMode.HALF_UP).longValue());
        }
        Long licenseCount = dashboardRespVO.getLicenseCount();
        if (licenseCount == 0) {
            dashboardRespVO.setCompletionRate(0L);
        } else {
            dashboardRespVO.setCompletionRate(BigDecimal.valueOf(dashboardRespVO.getPermanentCount()).multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(licenseCount), 0, RoundingMode.HALF_UP).longValue());
        }

        return dashboardRespVO;
    }

    @Override
    @LogRecord(type = SYSTEM_CUSTOMER_TYPE, subType = SYSTEM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}",
            success = SYSTEM_CUSTOMER_CREATE_SUCCESS)
    public Long createCustomer(CustomerSaveReqVO createReqVO) {
        // 校验客户名称和编号是否唯一
        validateCustomerNameAndCodeUnique(createReqVO.getName(), createReqVO.getCode(), createReqVO.getId());
        // 插入
        CustomerDO customer = BeanUtils.toBean(createReqVO, CustomerDO.class);
        customerMapper.insert(customer);

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

    @LogRecord(type = SYSTEM_CUSTOMER_TYPE, subType = SYSTEM_CUSTOMER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = SYSTEM_CUSTOMER_UPDATE_SUCCESS)
    @Override
    public void updateCustomer(CustomerSaveReqVO updateReqVO) {
        // 校验客户名称和编号是否唯一
        validateCustomerNameAndCodeUnique(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId());
        // 校验存在
        CustomerDO customerDO = validateCustomerExists(updateReqVO.getId());
        // 更新
        CustomerDO updateObj = BeanUtils.toBean(updateReqVO, CustomerDO.class);
        customerMapper.updateById(updateObj);

        if (updateReqVO.getPhone() == null) {
            updateReqVO.setPhone(customerDO.getPhone());
        }
        if (updateReqVO.getContacts() == null) {
            updateReqVO.setContacts(customerDO.getContacts());
        }
        if (updateReqVO.getRole() == null) {
            updateReqVO.setRole(customerDO.getRole());
        }
        // 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(customerDO, CustomerSaveReqVO.class));
        LogRecordContext.putVariable("customer", customerDO);
    }

    @Override
    @LogRecord(type = SYSTEM_CUSTOMER_TYPE, subType = SYSTEM_CUSTOMER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_CUSTOMER_DELETE_SUCCESS)
    public void deleteCustomer(Long id) {
        // 校验存在
        CustomerDO customerDO = validateCustomerExists(id);

        List<ProjectDO> projects = projectMapper.selectList(Wrappers.<ProjectDO>lambdaQuery().eq(ProjectDO::getCustomerId, id));
        if (CollUtil.isNotEmpty(projects)) {
            throw exception(CUSTOMER_EXISTS_PROJECT);
        }

        // 删除
        customerMapper.deleteById(id);

        LogRecordContext.putVariable("customer", customerDO);
    }

    private CustomerDO validateCustomerExists(Long id) {
        CustomerDO customerDO = customerMapper.selectById(id);
        if (customerDO == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }

        return customerDO;
    }

    private void validateCustomerNameAndCodeUnique(String name, String code, Long id) {
        Boolean isNameUnique = validateCustomerNameUnique(name, id);
        if (!isNameUnique) {
            throw exception(CUSTOMER_NAME_DUPLICATE, name);
        }
        Boolean isCodeUnique = validateCustomerCodeUnique(code, id);
        if (!isCodeUnique) {
            throw exception(CUSTOMER_CODE_DUPLICATE, code);
        }
    }

    @Override
    public CustomerDO getCustomer(Long id) {
        return customerMapper.selectById(id);
    }

    @Override
    public PageResult<CustomerDO> getCustomerPage(CustomerPageReqVO pageReqVO) {
        return customerMapper.selectPage(pageReqVO);
    }

    @Override
    public List<CustomerDO> getCustomerList() {
        return customerMapper.selectList();
    }

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

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

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

    @Override
    public ImportRespVO importList(List<CustomerImportRespVO> list, Boolean updateSupport) {
        if (CollUtil.isEmpty(list)) {
            throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
        }

        ImportRespVO respVO = ImportRespVO.builder().creates(new ArrayList<>())
                .updates(new ArrayList<>()).failures(new LinkedHashMap<>()).build();

        for (CustomerImportRespVO importRespVO : list) {
            CustomerDO customerDO = BeanUtils.toBean(importRespVO, CustomerDO.class);

            String name = customerDO.getName();
            if (StrUtil.isBlank(name)) {
                respVO.getFailures().put(name, "客户编号不能为空");
                continue;
            }
            if (StrUtil.isBlank(customerDO.getName())) {
                respVO.getFailures().put(name, "客户名称不能为空");
                continue;
            }
            if (customerDO.getType() == null) {
                respVO.getFailures().put(name, "客户类型不能为空");
                continue;
            }
            if (StrUtil.isBlank(customerDO.getContacts())) {
                respVO.getFailures().put(name, "联系人不能为空");
                continue;
            }

            try {
                customerDO.setAreaId(Long.valueOf(AreaUtils.parseArea(importRespVO.getAreaNames(), " ").getId()));
            } catch (Exception e) {
                log.info("导入地区转换失败：{}", importRespVO.getAreaNames());
            }
            if (customerDO.getAreaId() == null) {
                respVO.getFailures().put(name, "地区不能为空");
                continue;
            }

            CustomerDO customer = customerMapper.selectByCode(customerDO.getCode());
            if (customer == null) {
                customerMapper.insert(customerDO);
                respVO.getCreates().add(name);
                continue;
            }

            if (!updateSupport) {
                respVO.getFailures().put(name, "客户编号已存在");
                continue;
            }
            customerDO.setId(customer.getId());
            customerMapper.updateById(customerDO);
            respVO.getUpdates().add(name);
        }

        return respVO;
    }

    @Override
    public List<CustomerRespVO> getLicenseCustomers() {
        return customerMapper.getLicenseCustomers();
    }

}