package cn.cslg.pas.service;

import cn.cslg.pas.common.model.dto.AreaAddressDTO;
import cn.cslg.pas.common.model.params.PatentApplicantAddressParams;
import cn.cslg.pas.common.model.vo.PatentApplicantVO;
import cn.cslg.pas.common.utils.DateUtils;
import cn.cslg.pas.common.utils.PatentUtils;
import cn.cslg.pas.common.utils.Response;
import cn.cslg.pas.common.utils.SecurityUtils.LoginUtils;
import cn.cslg.pas.common.utils.StringUtils;
import cn.cslg.pas.domain.PatentApplicant;
import cn.cslg.pas.domain.PatentApplicantLink;
import cn.cslg.pas.domain.PatentApplicantMergeLink;
import cn.cslg.pas.domain.SystemDict;
import cn.cslg.pas.mapper.PatentApplicantMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 专利信息申请人表 服务类
 * </p>
 *
 * @author 王岩
 * @since 2022-02-24
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class PatentApplicantService extends ServiceImpl<PatentApplicantMapper, PatentApplicant> {

    private final PatentApplicantLinkService patentApplicantLinkService;
    private final PatentApplicantMergeLinkService patentApplicantMergeLinkService;
    private final AreaService areaService;
    private final SystemDictService systemDictService;
    private final LoginUtils loginUtils;

    public List<PatentApplicant> getPatentApplicantByIds(List<Integer> ids) {
        if (ids == null || ids.size() == 0) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<PatentApplicant> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(PatentApplicant::getId, ids);
        return this.list(queryWrapper);
    }

    public List<PatentApplicant> getPatentApplicantByPatentIds(List<Integer> patentIds) {
        List<PatentApplicantLink> patentApplicantLinkList = patentApplicantLinkService.getApplicantAttributesListByPatentIds(patentIds);
        List<Integer> applicantIds = patentApplicantLinkList.stream().map(PatentApplicantLink::getApplicantId).distinct().collect(Collectors.toList());
        List<PatentApplicant> patentApplicantList = this.getPatentApplicantByIds(applicantIds);
        return this.setPatentApplicantDataList(patentApplicantLinkList, patentApplicantList);
    }

    public List<PatentApplicant> getPatentApplicantByPatentId(Integer patentId) {
        List<PatentApplicantLink> patentApplicantLinkList = patentApplicantLinkService.getPatentApplicantAttributesByPatentId(patentId);
        List<Integer> applicantIds = patentApplicantLinkList.stream().map(PatentApplicantLink::getApplicantId).distinct().collect(Collectors.toList());
        List<PatentApplicant> patentApplicantList = this.getPatentApplicantByIds(applicantIds);
        return this.setPatentApplicantDataList(patentApplicantLinkList, patentApplicantList);
    }

    private List<PatentApplicant> setPatentApplicantDataList(List<PatentApplicantLink> patentApplicantLinkList, List<PatentApplicant> patentApplicantList) {
        List<PatentApplicant> dataList = new ArrayList<>();
        patentApplicantLinkList.forEach(attribute -> {
            PatentApplicant temp = patentApplicantList.stream().filter(applicant -> applicant.getId().equals(attribute.getApplicantId())).findFirst().orElse(null);
            if (temp != null) {
                PatentApplicant patentApplicant = new PatentApplicant();
                patentApplicant.setType(temp.getType());
                patentApplicant.setId(temp.getId());
                patentApplicant.setPatentId(attribute.getPatentId());
                patentApplicant.setName(temp.getName());
                patentApplicant.setShortName(temp.getShortName());
                patentApplicant.setCountry(temp.getCountry());
                patentApplicant.setProvinceId(temp.getProvinceId());
                patentApplicant.setCityId(temp.getCityId());
                patentApplicant.setAreaId(temp.getAreaId());
                patentApplicant.setAddressStr(temp.getAddressStr());
                patentApplicant.setOrder(attribute.getOrder());
                patentApplicant.setDataType(attribute.getType());
                dataList.add(patentApplicant);
            }
        });
        return dataList;
    }

    public IPage<PatentApplicant> getPageList(PatentApplicantVO params) {
        IPage<PatentApplicant> pageList = baseMapper.getPageList(new Page<>(params.getCurrent(), params.getSize()), params);
        List<SystemDict> systemDictList = systemDictService.getSystemDictListByType(Collections.singletonList("COUNTRIES"));
        pageList.getRecords().forEach(item -> item.setCountryName(systemDictList.stream().filter(systemDict -> systemDict.getValue().equals(item.getCountry())).findFirst().orElse(new SystemDict()).getLabel()));
        return pageList;
    }

    public IPage<PatentApplicant> getMergeList(PatentApplicantVO params) {
        LambdaQueryWrapper<PatentApplicant> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(params.getName())) {
            queryWrapper.like(PatentApplicant::getName, params.getName());
        }
        if (StringUtils.isNotEmpty(params.getCountry())) {
            queryWrapper.eq(PatentApplicant::getCountry, params.getCountry());
        }
        queryWrapper.eq(PatentApplicant::getProjectId, params.getProjectId());
        queryWrapper.eq(PatentApplicant::getMerge, true);
        IPage<PatentApplicant> pageList = this.page(new Page<>(params.getCurrent(), params.getSize()), queryWrapper);
        List<SystemDict> systemDictList = systemDictService.getSystemDictListByType(Collections.singletonList("COUNTRIES"));
        List<PatentApplicantMergeLink> linkList = patentApplicantMergeLinkService.getPatentApplicantMergeLinkListByProjectId(params.getProjectId());
        pageList.getRecords().forEach(item -> {
            List<PatentApplicantMergeLink> links = linkList.stream().filter(link -> link.getMergeId().equals(item.getId())).collect(Collectors.toList());
            item.setApplicantIds(links.stream().map(PatentApplicantMergeLink::getApplicantId).collect(Collectors.toList()));
            item.setCountryName(systemDictList.stream().filter(systemDict -> systemDict.getValue().equals(item.getCountry())).findFirst().orElse(new SystemDict()).getLabel());
        });
        return pageList;
    }

    public List<PatentApplicant> getApplicantListByNameList(List<String> nameList) {
        if (nameList == null || nameList.size() == 0) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<PatentApplicant> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(PatentApplicant::getName, nameList);
        return this.list(queryWrapper);
    }

    public PatentApplicant getPatentApplicantByName(String name, Integer projectId) {
        LambdaQueryWrapper<PatentApplicant> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PatentApplicant::getName, name);
        queryWrapper.eq(PatentApplicant::getProjectId, projectId);
        return this.getOne(queryWrapper);
    }

    public PatentApplicant add(String name, String shortName) {
        PatentApplicant applicant = new PatentApplicant();
        applicant.setName(name);
        applicant.setShortName(shortName);
        applicant.setCreateBy(0);
        applicant.setMerge(false);
        applicant.setType(PatentUtils.getIntKeyByOrganType(name));
        applicant.setUpdateTime(DateUtils.getDateTime());
        applicant.insert();
        return applicant;
    }

    private void setMergeData(Integer id, Integer projectId, List<Integer> applicantIds) {
        Set<Integer> ids = new HashSet<>();
        List<PatentApplicant> tempList = this.getPatentApplicantByIds(applicantIds);
        List<PatentApplicant> mergeList = tempList.stream().filter(PatentApplicant::getMerge).collect(Collectors.toList());
        List<PatentApplicant> commonList = tempList.stream().filter(item -> !item.getMerge()).collect(Collectors.toList());
        List<PatentApplicantMergeLink> tempListMerge = patentApplicantMergeLinkService.getPatentApplicantMergeLinkListByMergeId(id);
        ids.addAll(tempListMerge.stream().map(PatentApplicantMergeLink::getApplicantId).collect(Collectors.toList()));
        ids.addAll(commonList.stream().map(PatentApplicant::getId).collect(Collectors.toList()));
        mergeList.forEach(item -> {
            List<PatentApplicantMergeLink> patentApplicantMergeLinkList = patentApplicantMergeLinkService.getPatentApplicantMergeLinkListByMergeId(item.getId());
            this.delete(item.getId());
            ids.addAll(patentApplicantMergeLinkList.stream().map(PatentApplicantMergeLink::getApplicantId).collect(Collectors.toList()));
        });
        patentApplicantMergeLinkService.updatePatentApplicantMergeLink(id, projectId, new ArrayList<>(ids));
    }

    @Transactional
    public String add(PatentApplicant patentApplicant) {
        PatentApplicant temp = this.getPatentApplicantByName(patentApplicant.getName(), patentApplicant.getProjectId());
        if (temp != null) {
            return Response.error("名称已存在");
        }
        patentApplicant.setCreateBy(loginUtils.getId());
        patentApplicant.setUpdateTime(DateUtils.getDateTime());
        patentApplicant.insert();
        return Response.success(true);
    }

    @Transactional
    public String edit(PatentApplicant patentApplicant) {
        PatentApplicant temp = this.getPatentApplicantByName(patentApplicant.getName(), patentApplicant.getProjectId());
        if (temp != null && !temp.getId().equals(patentApplicant.getId())) {
            return Response.error("名称已存在");
        }
        patentApplicant.setUpdateTime(DateUtils.getDateTime());
        patentApplicant.updateById();
        if (patentApplicant.getMerge() && patentApplicant.getApplicantIds() != null && patentApplicant.getApplicantIds().size() != 0) {
            this.setMergeData(patentApplicant.getId(), patentApplicant.getProjectId(), patentApplicant.getApplicantIds());
        }
        return Response.success(true);
    }

    @Transactional
    public String delete(Integer id) {
        this.removeById(id);
        patentApplicantMergeLinkService.deleteByMergeId(id);
        return Response.success(true);
    }

    public String deleteMerge(Integer id, Integer mergeId) {
        patentApplicantMergeLinkService.deleteByMergeIdAndApplicantId(id, mergeId);
        return Response.success(true);
    }

    public void importPatentApplicant(Integer projectId, Integer localPatentId, Integer importPatentId, List<PatentApplicant> importPatentApplicantList, List<PatentApplicantLink> importPatentApplicantLinkList) {
        patentApplicantLinkService.deleteByPatentId(localPatentId);
        List<PatentApplicantLink> importPatentApplicantLinks = importPatentApplicantLinkList.stream().filter(item -> item.getPatentId().equals(importPatentId)).collect(Collectors.toList());
        List<Integer> importPatentApplicantIds = importPatentApplicantLinks.stream().map(PatentApplicantLink::getApplicantId).collect(Collectors.toList());
        List<PatentApplicant> importPatentApplicants = importPatentApplicantList.stream().filter(item -> importPatentApplicantIds.contains(item.getId())).collect(Collectors.toList());
        List<PatentApplicant> localPatentApplicantLists = this.getApplicantListByNameList(importPatentApplicants.stream().map(PatentApplicant::getName).collect(Collectors.toList()));
        for (PatentApplicant importPatentApplicant : importPatentApplicants) {
            PatentApplicant localPatentApplicant = localPatentApplicantLists.stream().filter(item -> item.getName().equals(importPatentApplicant.getName())).findFirst().orElse(null);
            Integer patentApplicantId;
            if (localPatentApplicant == null) {
                localPatentApplicant = new PatentApplicant();
                patentApplicantId = null;
            } else {
                patentApplicantId = localPatentApplicant.getId();
            }
            BeanUtils.copyProperties(importPatentApplicant, localPatentApplicant);
            localPatentApplicant.setId(patentApplicantId);
            localPatentApplicant.insertOrUpdate();
            List<PatentApplicantLink> patentApplicantLinkList = importPatentApplicantLinks.stream().filter(item -> item.getApplicantId().equals(importPatentApplicant.getId())).collect(Collectors.toList());
            for (PatentApplicantLink patentApplicantLink : patentApplicantLinkList) {
                patentApplicantLink.setId(null);
                patentApplicantLink.setApplicantId(localPatentApplicant.getId());
                patentApplicantLink.setPatentId(localPatentId);
            }
            patentApplicantLinkService.saveOrUpdateBatch(patentApplicantLinkList);
        }
    }

    /**
     * @param name      权利人 通过分割符 | 分割后的List
     * @param shortName 【标】权利人 通过分割符 | 分割后的List
     */
    public List<Integer> updatePatentApplicant(List<String> name, List<String> shortName, List<PatentApplicant> patentApplicantList) {
        //生成一个存放ID的List
        List<Integer> ids = new ArrayList<>();
        //判断当前名称是否为空
        if (name != null) {
            for (int i = 0; i < name.size(); i++) {
                String s = i < shortName.size() ? shortName.get(i) : "";
                s = s.replace((char) 12288, ' ');    // 将中文空格替换为英文空格
                s = s.trim();
                String nam = name.get(i);
                PatentApplicant temp = patentApplicantList.stream().filter(item -> item.getMerge().equals(false) && item.getName().equals(nam)).findFirst().orElse(null);
                if (temp == null) {
                    temp = this.add(name.get(i), s);
                } else if (name.size() == 1) {
                    temp.setShortName(s);
                    temp.updateById();
                }
                if (!ids.contains(temp.getId())) {
                    ids.add(temp.getId());
                }

            }
        } else {
            for (String s : shortName) {
                List<PatentApplicant> temp = patentApplicantList.stream().filter(item -> item.getMerge().equals(0) && item.getName().equals(s)).collect(Collectors.toList());
                PatentApplicant patentApplicant = new PatentApplicant();
                if (temp.size() == 0) {
                    patentApplicant = this.add(s, s);
                } else {
                    patentApplicant = temp.get(0);
                }

                if (!ids.contains(patentApplicant.getId())) {
                    ids.add(patentApplicant.getId());
                }
            }
        }

        return ids;
    }

    public void updatePatentApplicantAddress(PatentApplicantAddressParams params) {
        //用专利ID获取数据 申请人ID 申请人类型 申请人顺序
        List<PatentApplicantLink> patentApplicantLinkList = patentApplicantLinkService.getPatentApplicantAttributesByPatentId(params.getPatentId());
        //获取属于权利人的ID List 并且是第一位
        List<Integer> currentIds = patentApplicantLinkList.stream().filter(item -> item.getType().equals(1) && !item.getOrder().equals(0)).map(PatentApplicantLink::getApplicantId).collect(Collectors.toList());
        Integer firstCurrentId = patentApplicantLinkList.stream().filter(item -> item.getType().equals(1) && item.getOrder().equals(0)).map(PatentApplicantLink::getApplicantId).findFirst().orElse(null);
        List<Integer> originalIds = patentApplicantLinkList.stream().filter(item -> item.getType().equals(2) && item.getOrder().equals(0)).map(PatentApplicantLink::getApplicantId).collect(Collectors.toList());

        List<PatentApplicant> currentList = this.getPatentApplicantByIds(currentIds);
        PatentApplicant first = this.getById(firstCurrentId);
        List<PatentApplicant> originalList = this.getPatentApplicantByIds(originalIds);

        if (params.getCurrentAddress() != null) {
            for (int i = 0; i < params.getCurrentAddress().size(); i++) {
                int finalI = i;
                currentList.forEach(item -> {
                    AreaAddressDTO dto = areaService.getAreaAddressDTO(params.getCurrentAddress().get(finalI));
                    item.setAddressStr(params.getCurrentAddress().get(finalI));
                    item.setProvinceId(dto.getProvinceId());
                    item.setCityId(dto.getCityId());
                    item.setAreaId(dto.getAreaId());
                    item.updateById();
                });
            }
        }
        if (params.getCurrentCountry() != null) {
            for (int i = 0; i < params.getCurrentCountry().size(); i++) {
                int finalI = i;
                currentList.forEach(item -> {
                    item.setCountry(params.getCurrentCountry().get(finalI));
                    item.updateById();
                });
            }
        }
        if (params.getOriginalAddress() != null) {
            for (int i = 0; i < params.getOriginalAddress().size(); i++) {
                int finalI = i;
                originalList.forEach(item -> {
                    AreaAddressDTO dto = areaService.getAreaAddressDTO(params.getOriginalAddress().get(finalI));
                    item.setAddressStr(params.getOriginalAddress().get(finalI));
                    item.setProvinceId(dto.getProvinceId());
                    item.setCityId(dto.getCityId());
                    item.setAreaId(dto.getAreaId());
                    item.updateById();
                });
            }
        }
        if (params.getOriginalCountry() != null) {
            for (int i = 0; i < params.getOriginalCountry().size(); i++) {
                int finalI = i;
                originalList.forEach(item -> {
                    item.setCountry(params.getOriginalCountry().get(finalI));
                    item.updateById();
                });
            }
        }
        if (StringUtils.isNotEmpty(params.getFirstCurrentAddress()) && first != null) {
            AreaAddressDTO dto = areaService.getAreaAddressDTO(params.getFirstCurrentAddress());
            first.setAddressStr(params.getFirstCurrentAddress());
            first.setProvinceId(dto.getProvinceId());
            first.setCityId(dto.getCityId());
            first.setAreaId(dto.getAreaId());
            first.updateById();
        }
    }

}
