package com.fjhx.service.supplier.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.StorageBaseEntity;
import com.fjhx.entity.common.CommonFile;
import com.fjhx.entity.contract.Contract;
import com.fjhx.entity.supplier.Supplier;
import com.fjhx.entity.supplier.SupplierBank;
import com.fjhx.entity.supplier.SupplierContacts;
import com.fjhx.entity.supplier.SupplierKeep;
import com.fjhx.enums.MaterialTypeEnum;
import com.fjhx.mapper.supplier.SupplierMapper;
import com.fjhx.params.supplier.SupplierKeepVo;
import com.fjhx.params.supplier.SupplierVo;
import com.fjhx.service.common.CommonFileService;
import com.fjhx.service.contract.ContractService;
import com.fjhx.service.supplier.SupplierBankService;
import com.fjhx.service.supplier.SupplierContactsService;
import com.fjhx.service.supplier.SupplierKeepService;
import com.fjhx.service.supplier.SupplierService;
import com.fjhx.utils.BigDecimalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 供应商 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-08-08
 */
@Service
public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> implements SupplierService {

    @Autowired
    private SupplierBankService supplierBankService;

    @Autowired
    private SupplierContactsService supplierContactsService;

    @Autowired
    private SupplierKeepService supplierKeepService;

    @Autowired
    private CommonFileService commonFileService;

    @Autowired
    private ContractService contractService;

    private static final Object ADD_OBJ = new Object();

    @Override
    public Page<Map<String, Object>> getPage(Map<String, String> condition) {
        return baseMapper.getPage(createPage(condition), condition);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(SupplierVo supplierVo) {

        // TODO 创建供应商账号

        synchronized (ADD_OBJ) {
            String supplierCode = getSupplierCode();
            supplierVo.setCode(supplierCode);
            save(supplierVo);
        }

        Long id = supplierVo.getId();

        // 供应商收款账户
        SupplierBank supplierBank = supplierVo.getSupplierBank();
        supplierBank.setSupplierId(id);
        supplierBankService.save(supplierBank);

        // 供应商联系人
        SupplierContacts supplierContacts = supplierVo.getSupplierContacts();
        supplierContacts.setSupplierId(id);
        supplierContactsService.save(supplierContacts);

        // 供应商维护记录
        List<SupplierKeepVo> supplierKeepVoList = supplierVo.getSupplierKeepList();

        List<SupplierKeep> supplierKeepList = supplierKeepVoList.stream().map(item -> {
            // 赋值供应商id
            item.setSupplierId(id);

            // 绑定维护记录图片
            long fileLinkedId = IdWorker.getId();
            item.setFileLinkedId(fileLinkedId);
            commonFileService.add(fileLinkedId, item.getFileList());

            return BeanUtil.toBean(item, SupplierKeep.class);
        }).collect(Collectors.toList());
        supplierKeepService.saveBatch(supplierKeepList);

        // 其他资质
        List<CommonFile> otherQualifications = supplierVo.getOtherQualifications();
        commonFileService.add(id, otherQualifications);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(SupplierVo supplierVo) {
        updateById(supplierVo);

        Long id = supplierVo.getId();

        // 供应商收款账户
        SupplierBank supplierBank = supplierVo.getSupplierBank();
        if (supplierBank != null) {
            supplierBankService.updateById(supplierBank);
        }

        // 供应商联系人
        SupplierContacts supplierContacts = supplierVo.getSupplierContacts();
        if (supplierContacts != null) {
            supplierContactsService.updateById(supplierContacts);
        }

        // 供应商维护记录
        List<SupplierKeepVo> supplierKeepVoList = supplierVo.getSupplierKeepList();
        if (ObjectUtil.isNotEmpty(supplierKeepVoList)) {

            List<SupplierKeep> supplierKeepList = supplierKeepVoList.stream().map(item -> {
                // 赋值供应商id
                item.setSupplierId(id);

                Long fileLinkedId = item.getFileLinkedId();
                List<CommonFile> fileList = item.getFileList();
                if (ObjectUtil.isNotEmpty(fileLinkedId)) {
                    commonFileService.edit(fileLinkedId, fileList);
                } else {
                    fileLinkedId = IdWorker.getId();
                    item.setFileLinkedId(fileLinkedId);
                    commonFileService.add(fileLinkedId, item.getFileList());
                }

                return BeanUtil.toBean(item, SupplierKeep.class);
            }).collect(Collectors.toList());
            supplierKeepService.saveOrUpdateBatch(supplierKeepList);

        }

        // 其他资质
        List<CommonFile> otherQualifications = supplierVo.getOtherQualifications();
        commonFileService.edit(id, otherQualifications);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(SupplierVo supplierVo) {
        Long id = supplierVo.getId();
        removeById(id);

        supplierBankService.remove(SupplierBank::getSupplierId, id);
        supplierContactsService.remove(SupplierContacts::getSupplierId, id);

        List<SupplierKeep> list = supplierKeepService.list(SupplierKeep::getSupplierId, id);
        List<Long> fileList = list.stream().map(SupplierKeep::getFileLinkedId).collect(Collectors.toList());

        supplierKeepService.remove(SupplierKeep::getSupplierId, id);

        fileList.add(id);
        commonFileService.delete(fileList);
    }

    @Override
    public List<Map<String, Object>> getAccountDate() {
        List<Map<String, Object>> accountDate = baseMapper.getAccountDate();
        accountDate.forEach(item -> item.put("label", item.get("value") + "天（" + item.get("count") + "）"));
        return accountDate;
    }

    @Override
    public List<Map<String, Object>> getSafetyWarnDay() {
        List<Map<String, Object>> safetyWarnDayList = baseMapper.getSafetyWarnDay();

        safetyWarnDayList.forEach(item -> {
            Integer value = Convert.toInt(item.get("value"));
            Integer count = Convert.toInt(item.get("count"));
            String label;

            switch (value) {
                case 1:
                    label = getLabel("0~5天", count);
                    break;
                case 2:
                    label = getLabel("6~15天", count);
                    break;
                case 3:
                    label = getLabel("16~30天", count);
                    break;
                case 4:
                    label = getLabel("31~45天", count);
                    break;
                default:
                    label = getLabel("45天以上", count);
            }
            item.put("label", label);
        });

        return safetyWarnDayList;
    }

    @Override
    public List<Map<String, Object>> getStatistics(Map<String, String> condition) {

        List<Map<String, Object>> result = new ArrayList<>();

        // 统计全部数量
        HashMap<String, Object> allMap = new HashMap<>();
        Integer count = baseMapper.allCount(condition);
        allMap.put("label", "全部（" + count + "）");
        result.add(allMap);


        List<Map<String, Object>> list = baseMapper.getStatistics(condition);

        Map<Integer, Integer> map = list.stream().collect(Collectors.toMap(
                item -> Convert.toInt(item.get("type")),
                item -> Convert.toInt(item.get("count"))));

        for (int i = 0; i < 5; i++) {
            Map<String, Object> item = new HashMap<>();
            Integer itemCount = map.get(i);
            item.put("label", MaterialTypeEnum.getName(i) + "（" + (itemCount == null ? 0 : itemCount) + "）");
            item.put("value", i);
            result.add(item);
        }

        return result;
    }

    @Override
    public Page<Map<String, Object>> pagePurchase(Map<String, String> condition) {
        Page<Map<String, Object>> page = getPage(condition);

        List<Map<String, Object>> records = page.getRecords();
        if (records.size() == 0) {
            return page;
        }

        List<Long> idList = records.stream().map(item -> Convert.toLong(item.get("id"))).collect(Collectors.toList());

        List<Contract> list = contractService.list(Wrappers.<Contract>lambdaQuery()
                .in(Contract::getSupplierId, idList)
                .select(StorageBaseEntity::getCreateTime, Contract::getAmountMoney)
        );

        Map<Long, List<Contract>> listBySupplierId = list.stream().collect(Collectors.groupingBy(Contract::getSupplierId));

        // 当前日期
        Date date = new Date();
        // 今年开始时间
        Date year = DateUtil.beginOfYear(date);
        // 去年开始时间
        Date lastYear = DateUtil.offset(year, DateField.YEAR, -1);
        // 本月
        Date month = DateUtil.beginOfMonth(date);
        // 上月
        Date lastMonth = DateUtil.offsetMonth(month, -1);

        for (Map<String, Object> record : records) {
            Long supplierId = Convert.toLong(record.get("id"));
            List<Contract> contractList = listBySupplierId.get(supplierId);

            if (contractList == null) {
                record.put("sumMoney", BigDecimal.ZERO);
                record.put("lastYearMoney", BigDecimal.ZERO);
                record.put("yearMoney", BigDecimal.ZERO);
                record.put("lastMonthMoney", BigDecimal.ZERO);
                record.put("monthMoney", BigDecimal.ZERO);
                continue;
            }

            // 总额
            BigDecimal sumMoney = contractList.stream()
                    .map(Contract::getAmountMoney).reduce(BigDecimal.ZERO, BigDecimal::add);

            // 去年
            BigDecimal lastYearMoney = contractList.stream()
                    .filter(item -> BigDecimalUtil.ge(lastYear, item.getCreateTime()) && BigDecimalUtil.lt(year, item.getCreateTime()))
                    .map(Contract::getAmountMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 今年
            BigDecimal yearMoney = contractList.stream()
                    .filter(item -> BigDecimalUtil.ge(year, item.getCreateTime()))
                    .map(Contract::getAmountMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 上月
            BigDecimal lastMonthMoney = contractList.stream()
                    .filter(item -> BigDecimalUtil.ge(lastMonth, item.getCreateTime()) && BigDecimalUtil.lt(month, item.getCreateTime()))
                    .map(Contract::getAmountMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 本月
            BigDecimal monthMoney = contractList.stream()
                    .filter(item -> BigDecimalUtil.ge(month, item.getCreateTime()))
                    .map(Contract::getAmountMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            record.put("sumMoney", sumMoney);
            record.put("lastYearMoney", lastYearMoney);
            record.put("yearMoney", yearMoney);
            record.put("lastMonthMoney", lastMonthMoney);
            record.put("monthMoney", monthMoney);
        }

        return page;
    }

    /**
     * 生成label
     */
    private String getLabel(String str, Integer count) {
        return String.format("%s（%s）", str, count);
    }

    /**
     * 生成供应商编号
     */
    private String getSupplierCode() {
        Supplier supplier = getOne(Wrappers.<Supplier>lambdaQuery()
                .likeRight(Supplier::getCode, "C")
                .orderByDesc(Supplier::getCode).last("limit 1"));
        if (supplier == null) {
            return "C0001";
        }
        return "C" + (Convert.toInt(supplier.getCode().replace("C", "")) + 1);
    }

}
