/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.manager.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import org.apache.ibatis.annotations.Param;
import org.checkerframework.checker.units.qual.C;
import org.springblade.common.utils.BaiduApiUtil;
import org.springblade.common.utils.SnowFlakeUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.node.ForestNodeMerger;
import org.springblade.manager.dto.FindAllUserByConditionDTO;
import org.springblade.manager.dto.SaveUserInfoByProjectDTO;
import org.springblade.manager.entity.ContractInfo;
import org.springblade.manager.entity.ProjectContractArea;
import org.springblade.manager.entity.WbsTreeContract;
import org.springblade.manager.mapper.ProjectContractAreaMapper;
import org.springblade.manager.mapper.SaveUserInfoByProjectMapper;
import org.springblade.manager.mapper.WbsTreeContractMapper;
import org.springblade.manager.vo.*;
import org.springblade.manager.mapper.ContractInfoMapper;
import org.springblade.manager.service.IContractInfoService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.system.user.entity.User;
import org.springblade.system.user.vo.UserVO2;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 合同段信息表 服务实现类
 *
 * @author liuyc
 * @since 2022-04-14
 */
@Service
@AllArgsConstructor
public class ContractInfoServiceImpl
        extends BaseServiceImpl<ContractInfoMapper, ContractInfo>
        implements IContractInfoService {

    private final ContractInfoMapper contractInfoMapper;
    private final ProjectContractAreaMapper projectContractAreaMapper;
    private final SaveUserInfoByProjectMapper saveUserInfoByProjectMapper;
    private final WbsTreeContractMapper wbsTreeContractMapper;
    private final WbsTreeContractServiceImpl wbsTreeContractService;

    @Override
    public List<ContractInfo> selectContractByProjectIds(List<Long> ids) {
        return this.baseMapper.selectContractByProjectIds(ids);
    }

    @Override
    public IPage<ContractInfoVO> selectContractInfoPage(IPage<ContractInfoVO> page, ContractInfoVO contractInfo) {
        List<ContractInfoVO> dat = baseMapper.selectContractInfoPage(page, contractInfo);
        return page.setRecords(dat);
    }

    @Override
    public List<ContractInfo> selectContractInfoPageByPid(String pid) {
        return baseMapper.selectContractInfoPageByPid(pid);
    }

    @Override
    public List<CRolePostVO> findJobByRoleId(String id) {
        return contractInfoMapper.findJobByRoleId(id);
    }

    @Override
    public IPage<UserVO2> findAllUserByCondition(IPage<UserVO2> page, FindAllUserByConditionDTO values) {
        List<UserVO2> list = contractInfoMapper.findAllUserByCondition(page, values);
        return page.setRecords(list);
    }

    @Override
    public IPage<User> findUserListByCondition(IPage<User> page, FindAllUserByConditionDTO values) {
        List<User> userListByCondition = contractInfoMapper.findUserListByCondition(page, values);
        return page.setRecords(userListByCondition);
    }

    @Override
    public List<User> findUserInfoByCondition(String rId, String pId, String userName) {
        if (userName == null || ("").equals(userName)) {
            userName = "";
        }
        return contractInfoMapper.findUserInfoByCondition(rId, pId, userName);
    }


    @Override
    public List<User> findUserList() {
        return contractInfoMapper.findUserList();
    }

    @Override
    public Boolean updatePasswordByUserId(String userId, String password) {
        Integer row = contractInfoMapper.updatePasswordByUserId(userId, password);
        if (row > 0) {
            return true;
        }
        return false;
    }

    @Override
    public String selectStartFileId(String startFileUrl) {
//        return contractInfoMapper.selectStartFileId(startFileUrl);
        return null;
    }

    @Override
    public Boolean deleteFile(String url) {
        return contractInfoMapper.deleteFile(url);
    }

    @Override
    public List<WbsTreeContractTreeVO> tree(String wbsId, String projectId, String contractId) {
        return ForestNodeMerger.merge(baseMapper.tree(wbsId, projectId, contractId, null, null));
    }

    @Override
    public List<WbsTreeContractVO2> treeTwo(String projectId) {
        //查询当前项目下所有施工合同树根节点
        List<WbsTreeContractVO2> list = wbsTreeContractMapper.selectListByCondition(projectId);
        return list;
    }

    /**
     * 对客户端接口
     *
     * @param contractId 合同段ID
     * @param wbsType    需要查询的节点类型
     * @return 合同段自身的划分树
     */
    @Override
    public List<WbsTreeContractTreeVO> queryContractWbsTreeByContractIdAndType(String contractId, Integer wbsType, String parentId) {
        List<WbsTreeContractTreeVO> vo = this.baseMapper.tree(null, null, contractId, wbsType, parentId);
        return ForestNodeMerger.merge(vo);
    }

    @Override
    public List<WbsTreeContractTreeVO> queryContractWbsTreeAll(String contractId, Integer wbsType, String parentId) {
        return this.baseMapper.tree(null, null, contractId, wbsType, parentId);
    }


    /**
     * 新增合同段保存（施工-监理引用施工合同wbs私有树）
     *
     * @param contractInfo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAndUpdateContract(ContractInfoVO contractInfo) {
        //新增操作
        if (contractInfo.getId() == null) {
            List<ContractInfo> contractInfos = baseMapper.selectList(Wrappers.<ContractInfo>query().lambda()
                    .eq(ContractInfo::getContractName, contractInfo.getContractName())
                    .eq(ContractInfo::getPId, contractInfo.getPId())
            );
            if (contractInfos.size() > 0) {
                throw new ServiceException("合同段名称已存在当前项目下,请重新输入");
            }
            if (StringUtils.isEmpty(String.valueOf(contractInfo.getContractType()))) {
                throw new ServiceException("合同类型不能为空");
            }
            //新增合同段
            boolean row = saveOrUpdate(contractInfo);
            //新增contract_type=2监理或=3指挥部（业主）类型Wbs树
            if (contractInfo.getContractType().equals(2) || contractInfo.getContractType().equals(3)) {
                List<WbsTreeContractVO3> infos = contractInfo.getIdList();
                infos.stream().forEach(info -> {
                    List<WbsTreeContract> wbsTreeContracts = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>query().lambda()
                            .eq(WbsTreeContract::getContractId, info.getContractId())
                    );
                    //初始化
                    wbsTreeContracts.stream().forEach(i -> {
                        Long id = SnowFlakeUtil.getId();
                        i.setPKeyId(id);
                        i.setContractIdRelation(i.getContractId());
                        i.setContractId(String.valueOf(contractInfo.getId()));
                        i.setContractType(contractInfo.getContractType());
                    });
                    //新增合同段wbs树
                    wbsTreeContractService.saveBatch(wbsTreeContracts);
                });
            }
            return submitContractRelevantInfo(row, contractInfo);

        } else {
            //编辑修改操作
            List<ContractInfo> contractInfos = baseMapper.selectList(Wrappers.<ContractInfo>query().lambda()
                    .eq(ContractInfo::getContractName, contractInfo.getContractName())
                    .eq(ContractInfo::getPId, contractInfo.getPId())
                    .ne(ContractInfo::getId, contractInfo.getId())
            );
            if (contractInfos.size() > 0) {
                throw new ServiceException("合同段名称已存在当前项目下,请重新输入");
            }
            if (StringUtils.isEmpty(String.valueOf(contractInfo.getContractType()))) {
                throw new ServiceException("合同类型不能为空");
            }
            boolean row = saveOrUpdate(contractInfo);
            if (contractInfo.getContractType().equals(2) || contractInfo.getContractType().equals(3)) {
                List<String> idList1 = new ArrayList<>();  //当前所有入参施工合同根节点合同id
                List<String> idList2 = new ArrayList<>();  //当前所有已引用监理或业主根节点合同引用id
                List<WbsTreeContractVO3> list = contractInfo.getIdList();
                if (list.size() > 0) {
                    list.stream().forEach(cId -> {
                        //获取入参根节点id
                        String contractId = cId.getContractId();
                        idList1.add(contractId);
                    });
                }
                //查询当前所有已引用监理或业主根节点合同引用id
                List<WbsTreeContract> wbsTreeContracts = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>query().lambda()
                        .eq(WbsTreeContract::getContractId, contractInfo.getId())
                        .eq(WbsTreeContract::getContractType, contractInfo.getContractType())
                        .eq(WbsTreeContract::getStatus, 1)
                        .eq(WbsTreeContract::getParentId, 0)
                );
                wbsTreeContracts.stream().forEach(id -> {
                    String contractIdRelation = id.getContractIdRelation();
                    idList2.add(String.valueOf(contractIdRelation));
                });
                List<String> result = getDiffrent(idList1, idList2);
                if (idList1.size() > idList2.size()) {
                    //新增
                    result.stream().forEach(id -> {
                        //查询当前需要引用的施工合同wbs树根节点信息
                        WbsTreeContract wbsTreeContract = wbsTreeContractMapper.selectOne(Wrappers.<WbsTreeContract>query().lambda()
                                .eq(WbsTreeContract::getContractId, id)
                                .eq(WbsTreeContract::getParentId, 0)
                                .eq(WbsTreeContract::getContractType, 1)
                        );
                        WbsTreeContract wbsTreeContractsIsDeleted = wbsTreeContractMapper.selectCondition(contractInfo.getId(), wbsTreeContract.getId(), id, contractInfo.getContractType());
                        if (wbsTreeContractsIsDeleted != null) {
                            //修改 通过当前合同id = contractInfo.getId() , 监理或业主关联的合同段id = contractIdRelation
                            wbsTreeContractMapper.updateByCondition2(contractInfo.getId(), wbsTreeContractsIsDeleted.getContractIdRelation());
                        } else {
                            //新增 根据施工合同根节点查询当前根节点下的施工合同wbs树+表
                            List<WbsTreeContract> wbsTreeContractsList = wbsTreeContractMapper.selectList(Wrappers.<WbsTreeContract>query().lambda()
                                    .eq(WbsTreeContract::getContractId, id)
                                    .eq(WbsTreeContract::getContractType, 1)
                            );
                            //初始化
                            wbsTreeContractsList.stream().forEach(i -> {
                                Long id1 = SnowFlakeUtil.getId();
                                i.setPKeyId(id1);
                                i.setContractIdRelation(i.getContractId());
                                i.setContractId(String.valueOf(contractInfo.getId()));
                                i.setContractType(contractInfo.getContractType());
                            });
                            wbsTreeContractService.saveBatch(wbsTreeContractsList);
                        }
                    });
                } else {
                    result.stream().forEach(id -> {
                        //根据关联项目id = getContractIdRelation 删除树
                        wbsTreeContractMapper.delete(Wrappers.<WbsTreeContract>update().lambda()
                                .set(WbsTreeContract::getIsDeleted, 1)
                                .eq(WbsTreeContract::getContractIdRelation, id)
                                .eq(WbsTreeContract::getProjectId, contractInfo.getPId())
                                .eq(WbsTreeContract::getContractId, contractInfo.getId())
                        );
                    });
                }
            }
            return submitContractRelevantInfo(row, contractInfo);
        }
    }

    private boolean submitContractRelevantInfo(boolean row, ContractInfoVO contractInfo) {
        if (row) {
            //绑定用户角色信息
            List<SaveUserInfoByProjectDTO> list = saveUserInfoByProjectMapper.selectList(Wrappers.<SaveUserInfoByProjectDTO>query().lambda()
                    .eq(SaveUserInfoByProjectDTO::getProjectId, contractInfo.getPId())
                    .isNull(SaveUserInfoByProjectDTO::getContractId)
            );
            if (list.size() > 0) {
                Long contractId = contractInfo.getId();
                list.stream().forEach(i -> {
                    i.setContractId(String.valueOf(contractId));
                    saveUserInfoByProjectMapper.updateById(i);
                });
            }
            //获取位置信息初始化
            String projectPlace = contractInfo.getProjectPlace();
            try {
                Map<String, Object> addressInfo = BaiduApiUtil.geocoding(projectPlace);
                Map<String, String> position = BaiduApiUtil.getPosition(addressInfo.get("lat").toString()
                        + "," + addressInfo.get("lng").toString());
                ProjectContractArea projectContractArea = new ProjectContractArea();
                projectContractArea.setProvince(position.get("province"));
                projectContractArea.setCity(position.get("city"));
                projectContractArea.setCounty(position.get("district"));
                projectContractArea.setCity_code(position.get("adcode"));
                projectContractArea.setProjectId(contractInfo.getPId());
                projectContractArea.setIsDeleted(0);
                projectContractArea.setContractId(String.valueOf(contractInfo.getId()));
                QueryWrapper<ProjectContractArea> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("project_id", contractInfo.getPId());
                queryWrapper.eq("contract_id", contractInfo.getId());
                queryWrapper.eq("province", position.get("province"));
                queryWrapper.eq("city", position.get("city"));
                queryWrapper.eq("county", position.get("district"));
                queryWrapper.eq("city_code", position.get("adcode"));
                queryWrapper.eq("is_deleted", contractInfo.getIsDeleted());
                ProjectContractArea projectContractArea1 = projectContractAreaMapper.selectOne(queryWrapper);
                if (projectContractArea1 == null) {
                    int res = projectContractAreaMapper.insert(projectContractArea);
                    return res > 0;
                }
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    private static List<String> getDiffrent(List<String> list1, List<String> list2) {
        List<String> diff = new ArrayList<String>();
        List<String> maxList = list1;
        List<String> minList = list2;
        if (list2.size() > list1.size()) {
            maxList = list2;
            minList = list1;
        }
        Map<String, Integer> map = new HashMap<String, Integer>(maxList.size());
        for (String string : maxList) {
            map.put(string, 1);
        }
        for (String string : minList) {
            if (map.get(string) != null) {
                map.put(string, 2);
                continue;
            }
            diff.add(string);
        }
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            if (entry.getValue() == 1) {
                diff.add(entry.getKey());
            }
        }
        return diff;
    }


    @Override
    public List<ContractInfo> findContractInProject(String ids) {
        return baseMapper.selectList(Wrappers.<ContractInfo>query().lambda().eq(ContractInfo::getPId, ids));
    }

    @Override
    public ContractInfo selectById(String contractId) {
        return baseMapper.selectById(contractId);
    }

    @Override
    public ContractInfoVO2 selectByCondition(ContractInfo contractInfo) {
        ContractInfo contractInfo1 = baseMapper.selectById(contractInfo.getId());
        ContractInfoVO2 contractInfoVO2 = new ContractInfoVO2();
        contractInfoVO2.setContractInfo(contractInfo1);
        Integer contractType = contractInfo1.getContractType();
        List<WbsTreeContractVO3> list = baseMapper.selectLists(contractInfo, contractType);
        contractInfoVO2.setWbsTreeContractList(list);
        return contractInfoVO2;
    }
}
