package com.kcim.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kcim.common.constants.NumberConstant;
import com.kcim.common.exception.CostException;
import com.kcim.common.util.PageUtils;
import com.kcim.common.util.UserContext;
import com.kcim.dao.model.Accounting;
import com.kcim.dao.model.AccountingItemMap;
import com.kcim.dao.model.OrderItemMap;
import com.kcim.dao.repository.AccountingItemMapRepository;
import com.kcim.dao.repository.AccountingRepository;
import com.kcim.service.AccountingItemMapService;
import com.kcim.service.DrugService;
import com.kcim.service.ItemService;
import com.kcim.service.MaterialService;
import com.kcim.web.request.AccountingItemMapRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

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

/**
 * @program: CostAccount
 * @description:
 * @author: Wang.YS
 * @create: 2023-11-27 17:52
 **/
@Service("AccountingItemMapService")
@Slf4j
@AllArgsConstructor
public class AccountingItemMapServiceImpl implements AccountingItemMapService {

    AccountingItemMapRepository repository;

    AccountingRepository accountingRepository;
    DrugService drugService;

    MaterialService materialService;

    ItemService itemService;
    /**
     * 获取会计科目收入列表
     * @param accountingName 会计科目名称
     * @param type 筛选类型 0全部 1已对照 2未对照
     * @return 列表
     */
    @Override
    public Object getAccountingList(String accountingName, Integer type) {
        List<Accounting> accountingList = accountingRepository.getAccountIncome(accountingName);
        List<Accounting> allIncome = accountingRepository.getAllIncome();
        if(CollectionUtils.isEmpty(accountingList)){
            return new ArrayList<>();
        }
        List<AccountingItemMap> itemMaps = repository.getList();
        if(CollectionUtils.isEmpty(itemMaps)){
            //无对照数据 返回会计科目全部
            List<Accounting> collect = accountingList.stream().filter(f -> !f.getParentId().equals(NumberConstant.ZERO_L)).collect(Collectors.toList());
            Map<Long, Accounting> accountingMap = allIncome.stream().collect(Collectors.toMap(Accounting::getId, accounting -> accounting, (a, b) -> b));
            List<Accounting> parentAccounting = new ArrayList<>();

            for (Accounting accounting1 : collect) {
                getParentAccount(accounting1, accountingMap, parentAccounting);
            }
            if(!CollectionUtils.isEmpty(parentAccounting)){
                accountingList.addAll(parentAccounting);
            }
            List<Accounting> accounting = accountingList.stream().distinct().collect(Collectors.toList());
            return   accounting.stream().filter(o -> o.getParentId() == 0)
                    .peek(o -> o.setChildren(this.getAccountTree(o, accounting)))
                    .collect(Collectors.toList());
        }else {
            if(type.equals(NumberConstant.ONE)){
                //已对照
                List<String> accountCodes = itemMaps.stream().map(AccountingItemMap::getAccountingCode).distinct().collect(Collectors.toList());
                List<Accounting> returnList = new ArrayList<>();
                for (Accounting accountVO : accountingList) {
                    if(accountCodes.contains(accountVO.getAccountingCode())){
                        returnList.add(accountVO);
                    }
                }
                if(!CollectionUtils.isEmpty(returnList)){
                    //找出父类不是0的数据 递归找到父类组装成树
                    List<Accounting> collect = returnList.stream().filter(f -> !f.getParentId().equals(NumberConstant.ZERO_L)).collect(Collectors.toList());
                    List<Accounting> parentAccounting = new ArrayList<>();
                    Map<Long, Accounting> accountingMap = allIncome.stream().collect(Collectors.toMap(Accounting::getId, accounting -> accounting, (a, b) -> b));
                    collect.forEach(accounting -> getParentAccount(accounting, accountingMap, parentAccounting));
                    if(!CollectionUtils.isEmpty(parentAccounting)){
                        returnList.addAll(parentAccounting);
                    }
                    List<Accounting> accounting = returnList.stream().distinct().collect(Collectors.toList());
                    return accounting.stream().filter(o -> o.getParentId() == 0)
                            .peek(o -> o.setChildren(this.getAccountTree(o, accounting)))
                            .collect(Collectors.toList());
                }
            } else if (type.equals(NumberConstant.TWO)) {
                //未对照
                List<String> accountCodes = itemMaps.stream().map(AccountingItemMap::getAccountingCode).distinct().collect(Collectors.toList());
                List<Accounting> returnList = new ArrayList<>();
                for (Accounting accountVO : accountingList) {
                    if(!accountCodes.contains(accountVO.getAccountingCode())){
                        returnList.add(accountVO);
                    }
                }
                if(!CollectionUtils.isEmpty(returnList)){
                    //找出父类不是0的数据 递归找到父类组装成树
                    List<Accounting> collect = returnList.stream().filter(f -> !f.getParentId().equals(NumberConstant.ZERO_L)).collect(Collectors.toList());
                    List<Accounting> parentAccounting = new ArrayList<>();
                    Map<Long, Accounting> accountingMap = allIncome.stream().collect(Collectors.toMap(Accounting::getId, accounting -> accounting, (a, b) -> b));
                    collect.forEach(accounting -> getParentAccount(accounting, accountingMap, parentAccounting));
                    if(!CollectionUtils.isEmpty(parentAccounting)){
                        returnList.addAll(parentAccounting);
                    }
                    List<Accounting> accounting = returnList.stream().distinct().collect(Collectors.toList());
                    return accounting.stream().filter(o -> o.getParentId() == 0)
                            .peek(o -> o.setChildren(this.getAccountTree(o, accounting)))
                            .collect(Collectors.toList());
                }
            }else {
                //全部
                List<Accounting> collect = accountingList.stream().filter(f -> !f.getParentId().equals(NumberConstant.ZERO_L)).collect(Collectors.toList());
                Map<Long, Accounting> accountingMap = allIncome.stream().collect(Collectors.toMap(Accounting::getId, accounting -> accounting, (a, b) -> b));
                List<Accounting> parentAccounting = new ArrayList<>();

                collect.forEach(accounting -> getParentAccount(accounting, accountingMap, parentAccounting));
                if(!CollectionUtils.isEmpty(parentAccounting)){
                    accountingList.addAll(parentAccounting);
                }
                List<Accounting> accounting = accountingList.stream().distinct().collect(Collectors.toList());
                return   accounting.stream().filter(o -> o.getParentId() == 0)
                        .peek(o -> o.setChildren(this.getAccountTree(o, accounting)))
                        .collect(Collectors.toList());
            }
        }
        return new ArrayList<>();
    }

    /**
     * 递归查找父类代码
     * @param accounting 当前会计科目
     * @param accountingMap 所有会计科目
     * @param parentAccounting 父类会计科目
     */
    private void getParentAccount(Accounting accounting,Map<Long,Accounting> accountingMap,List<Accounting> parentAccounting ){
        Accounting parentAccount = accountingMap.get(accounting.getParentId());
        if(Objects.nonNull(parentAccount)){
            parentAccounting.add(parentAccount);
            if(!parentAccount.getParentId().equals(NumberConstant.ZERO_L)){
                getParentAccount(parentAccount, accountingMap, parentAccounting );
            }
        }

    }

    private List<Accounting> getAccountTree(Accounting accountVO, List<Accounting> list) {
        return list.stream().filter(o -> o.getParentId().equals(accountVO.getId()))
                .peek(o -> o.setChildren(this.getAccountTree(o, list)))
                .collect(Collectors.toList());
    }
    /**
     * 获取收费项目字典
     * @param type 类型 1 药品 2 材料 3 项目
     * @param name  项目名称
     * @return 字典列表
     */
    @Override
    public Object getAccountingItemDictList(Integer type, String name) {
        List<OrderItemMap> orderItemMaps = new ArrayList<>();
        if(type.equals(NumberConstant.ONE)){
            //药品
            orderItemMaps = drugService.getItemDict(name);
        } else if (type.equals(NumberConstant.TWO)) {
            //材料
            orderItemMaps = materialService.getItemDict(name);
        } else {
            orderItemMaps = itemService.getItemDict(name);
        }
        //获取已对照的项目
        List<AccountingItemMap> itemMaps = repository.getList();
        if(!CollectionUtils.isEmpty(itemMaps)){
            List<String> list = itemMaps.stream().map(AccountingItemMap::getItemCode).collect(Collectors.toList());
            List<OrderItemMap> removeList = orderItemMaps.stream().filter(orderItemMap -> list.contains(orderItemMap.getItemCode())).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(removeList)){
                orderItemMaps.removeAll(removeList);
            }

        }
        return orderItemMaps;
    }

    /**
     * 获取会计科目
     * @param current 当前页
     * @param pageSize 页容量
     * @param accountingCode 会计科目代码
     * @param itemName 项目名称
     * @return 对照列表
     */
    @Override
    public Object getAccountingItemMap(Integer current, Integer pageSize, String accountingCode, String itemName) {
        Page<AccountingItemMap> page = repository.getPage(current, pageSize, accountingCode, itemName);
        List<AccountingItemMap> records = page.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return new PageUtils(new ArrayList<>(),NumberConstant.ZERO,pageSize,current);
        }
        for (AccountingItemMap record : records) {
            //"药品_1","材料_2","项目_3"
            String itemType = record.getType();
            switch (itemType) {
                case "1":
                    record.setTypeName("药品");
                    break;
                case "2":
                    record.setTypeName("材料");
                    break;
                case "3":
                    record.setTypeName("项目");
                    break;
                default:
                    record.setTypeName("未知");
                    break;
            }
        }
        return new PageUtils(records, Math.toIntExact(page.getTotal()),pageSize,current);
    }

    /**
     * 添加会计科目项目对照
     * @param map 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addAccountingItemMap(AccountingItemMapRequest map) {
        List<AccountingItemMap> itemMaps = map.getItemMaps();
        if(CollectionUtils.isEmpty(itemMaps)){
            throw new CostException("未找到需要保存的数据");
        }

        for (AccountingItemMap itemMap : itemMaps) {
            itemMap.setHospId(UserContext.getHospId());
            itemMap.setCreateTime(new Date());
            itemMap.setCreateUser(String.valueOf(UserContext.getCurrentUser().getId()));
            itemMap.setAccountingCode(map.getAccountingCode());
            itemMap.setAccountingName(map.getAccountingName());
        }
        repository.saveBatch(itemMaps);

    }

    /**
     * 单个删除
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void deleteAccountingItemMap(Integer id) {
        repository.batchDelete(Collections.singletonList(id));

    }

    /**
     * 批量删除
     * @param ids 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void batchDeleteAccountingItemMap(List<Integer> ids) {
        repository.batchDelete(ids);
    }
}
