package com.yeejoin.amos.boot.module.tzs.flc.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yeejoin.amos.boot.biz.common.constants.CommonConstant;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
import com.yeejoin.amos.boot.biz.common.utils.TreeParser;
import com.yeejoin.amos.boot.module.common.api.entity.OrgUsr;
import com.yeejoin.amos.boot.module.common.biz.service.impl.OrgUsrServiceImpl;
import com.yeejoin.amos.boot.module.tzs.api.dto.BaseUnitLicenceDto;
import com.yeejoin.amos.boot.module.tzs.api.entity.BaseUnitLicence;
import com.yeejoin.amos.boot.module.tzs.api.entity.RegUnitInfo;
import com.yeejoin.amos.boot.module.tzs.api.entity.TzBaseEnterpriseInfo;
import com.yeejoin.amos.boot.module.tzs.api.service.IRegUnitInfoService;
import com.yeejoin.amos.boot.module.tzs.biz.service.impl.BaseUnitLicenceServiceImpl;
import com.yeejoin.amos.boot.module.tzs.biz.service.impl.TzBaseEnterpriseInfoServiceImpl;
import com.yeejoin.amos.boot.module.tzs.biz.service.impl.TzsAuthServiceImpl;
import com.yeejoin.amos.boot.module.tzs.flc.api.dto.RegUnitIcDto;
import com.yeejoin.amos.boot.module.tzs.flc.api.dto.RegUnitInfoDto;
import com.yeejoin.amos.boot.module.tzs.flc.api.entity.RegUnitIc;
import com.yeejoin.amos.boot.module.tzs.flc.api.enums.UnitReviewStateEnum;
import com.yeejoin.amos.boot.module.tzs.flc.api.mapper.RegUnitInfoMapper;
import com.yeejoin.amos.component.feign.config.InnerInvokException;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import com.yeejoin.amos.feign.privilege.model.RoleModel;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.rdbms.service.BaseService;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

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

/**
 * 单位注册信息表服务实现类
 *
 * @author system_generator
 * @date 2022-08-09
 */
@Service
public class RegUnitInfoServiceImpl extends BaseService<RegUnitInfoDto, RegUnitInfo, RegUnitInfoMapper> implements IRegUnitInfoService {

    @Autowired
    BaseUnitLicenceServiceImpl baseUnitLicenceService;

    @Autowired
    DataDictionaryServiceImpl iDataDictionaryService;

    @Autowired
    OrgUsrServiceImpl iOrgUsrService;

    @Autowired
    RegUnitIcServiceImpl regUnitIcService;

    @Autowired
    private TzsAuthServiceImpl tzsAuthServiceImpl;

    @Autowired
    TzBaseEnterpriseInfoServiceImpl tzBaseEnterpriseInfoService;

    @Autowired
    RestTemplate restTemplate;

    /**
     * 使用单位的类型，数据来源：cb_data_dictionary code = 1232
     */
    private static String USE_UNIT_TYPE_CODE = "1232";

    /**
     * 单位类型，数据来源：cb_data_dictionary type = UNIT_TYPE
     */
    private static String DICT_TYPE_UNIT_TYPE = "UNIT_TYPE_NEW";


    @Override
    @Transactional(rollbackFor = Exception.class)
    public RegUnitInfoDto registerUnit(RegUnitInfoDto model) {
        tzsAuthServiceImpl.setRequestContext();
        // 1.插入注册单位基本信息表：tz_flc_reg_unit_info
        RegUnitInfo regUnitInfo = new RegUnitInfo();
        // 注册用统一信用码注册，默认证件类型为营业执照，数据来源：cb_data_dictionary code = 1060
        model.setUnitCodeType("1060");
        Bean.copyExistPropertis(model, regUnitInfo);
        // 2.插入单位注册许可信息表：tz_base_unit_licence
        List<BaseUnitLicenceDto> unitLicenceDtos = model.getUnitLicences();
        List<BaseUnitLicence> baseUnitLicences = unitLicenceDtos.stream().map(s -> {
            s.setUnitCode(model.getUnitCode());
            s.setUnitName(model.getName());
            BaseUnitLicence target = new BaseUnitLicence();
            Bean.copyExistPropertis(s, target);
            return target;
        }).collect(Collectors.toList());
        baseUnitLicenceService.saveOrUpdateBatch(baseUnitLicences);
        // 3.插入工商单位信息表：tz_flc_reg_unit_ic
        RegUnitIc regUnitIc = new RegUnitIc();
        model.getRegUnitIc().setUnitCode(model.getUnitCode());
        model.getRegUnitIc().setUnitName(model.getName());
        Bean.copyExistPropertis(model.getRegUnitIc(), regUnitIc);
        regUnitIcService.save(regUnitIc);
        // 4.调用平台进行创建单位、用户信息,同步用户信息
        if (UnitReviewStateEnum.NO_NEED_REVIEW.getCode().equals(model.getState())) {
            // 4.1 自动创建：调用平台进行创建单位、用户信息
            this.createCompanyAndUser(regUnitInfo);
            // 4.2 创建企业信息
            this.createBaseEnterpriseInfo(model);
        }
        this.save(regUnitInfo);
        // 5.组织返回数据
        // 5.1企业基本信息
        Bean.copyExistPropertis(regUnitInfo, model);
        // 5.2行政许可数据
        model.setUnitLicences(Bean.toModels(baseUnitLicences, BaseUnitLicenceDto.class));
        //  5.3工商信息
        model.setRegUnitIc(Bean.toModel(regUnitIc, new RegUnitIcDto()));
        return model;
    }

    public void createBaseEnterpriseInfo(RegUnitInfoDto regUnitInfo) {
        TzBaseEnterpriseInfo baseEnterpriseInfo = new TzBaseEnterpriseInfo();
        baseEnterpriseInfo.setUnitType(regUnitInfo.getUnitType());
        baseEnterpriseInfo.setUseCode(regUnitInfo.getUnitCode());
        baseEnterpriseInfo.setProvince(regUnitInfo.getProvince());
        baseEnterpriseInfo.setCity(regUnitInfo.getCity());
        baseEnterpriseInfo.setDistrict(regUnitInfo.getDistrict());
        baseEnterpriseInfo.setStreet(regUnitInfo.getStree());
        baseEnterpriseInfo.setCommunity(regUnitInfo.getCommunity());
        baseEnterpriseInfo.setAddress(regUnitInfo.getAddress());
        baseEnterpriseInfo.setLegalPerson(regUnitInfo.getLegalPerson());
        baseEnterpriseInfo.setLegalPhone(regUnitInfo.getLegalPersonTel());
        baseEnterpriseInfo.setUseContact(regUnitInfo.getContactPerson());
        baseEnterpriseInfo.setContactPhone(regUnitInfo.getContactPersonTel());
        baseEnterpriseInfo.setLongitude(regUnitInfo.getLongitude());
        baseEnterpriseInfo.setLatitude(regUnitInfo.getLatitude());
        baseEnterpriseInfo.setGoverningBody(regUnitInfo.getManagementUnit());
        baseEnterpriseInfo.setDataSources("企业注册");
        baseEnterpriseInfo.setIndustry(regUnitInfo.getRegUnitIc().getIndustryName());
        baseEnterpriseInfo.setRegistrationAuthority(regUnitInfo.getRegUnitIc().getRegisteredOrgan());
        baseEnterpriseInfo.setApprovalTime(regUnitInfo.getRegUnitIc().getApprovedDate());
        baseEnterpriseInfo.setOperatingStatus(regUnitInfo.getRegUnitIc().getBusinessState());
        baseEnterpriseInfo.setSyncDate(new Date());
        baseEnterpriseInfo.setSyncState(0);
        tzBaseEnterpriseInfoService.save(baseEnterpriseInfo);
    }

    @Override
    public RegUnitInfoDto unitCheck(String unitCode, String unitType) {
        // 1.校验重复性
        RegUnitInfo regUnitInfo = this.getOne(new LambdaQueryWrapper<RegUnitInfo>().eq(RegUnitInfo::getUnitCode, unitCode));
        if (regUnitInfo != null) {
            throw new RuntimeException("该单位已注册，请联系企业管理员！");
        }
        // 2.组织返回数据
        RegUnitInfoDto regUnitInfoDto = new RegUnitInfoDto();
        if (USE_UNIT_TYPE_CODE.equals(unitType)) {
            // 2.1 使用单位调用行政许可系统接口进行查询工商信息
//            MultiValueMap<String, String> headers = new HttpHeaders();
//            headers.add("header-1","v1");
//            headers.add("header-2","v2");
//            RequestEntity requestEntity = new RequestEntity(
//                    null, //body部分数据
//                    headers, //头
//                    HttpMethod.GET,//请求方法
//                    URI.create("url"));
//            ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(requestEntity,JSONObject.class);
//            JSONObject result = responseEntity.getBody();
            // 2.2 工商信息组装
//            regUnitInfoDto.setRegUnitIc();
        } else {
            RegUnitIc regUnitIc = regUnitIcService.getOne(new LambdaQueryWrapper<RegUnitIc>().eq(RegUnitIc::getUnitCode, unitCode));
            regUnitInfoDto.setRegUnitIc(Bean.toModel(regUnitIc, new RegUnitIcDto()));
        }
        // 2.3 许可信息组装
        List<BaseUnitLicence> unitLicences = baseUnitLicenceService.list(new LambdaQueryWrapper<BaseUnitLicence>().eq(BaseUnitLicence::getUnitCode, unitCode));
        regUnitInfoDto.setUnitLicences(Bean.toModels(unitLicences, BaseUnitLicenceDto.class));
        return regUnitInfoDto;
    }

    @Override
    public List<DataDictionary> getUnitTypeList() {
        return iDataDictionaryService.getByType(DICT_TYPE_UNIT_TYPE);
    }

    @Override
    public Collection getManagementUnitTree() {
        // 组织架构中单位级别为：省级、地市级、区县级的单位
        Collection<CompanyModel> companyModels = Privilege.companyClient.companyTreeWithoutAuth().getResult();
        return companyModels.stream().filter(c -> "headquarter".equals(c.getLevel()) || "prefecture-level".equals(c.getLevel()) || "county".equals(c.getLevel())).map(this::dealChildCompany).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean unitLogOut(String unitCode) {
        tzsAuthServiceImpl.setRequestContext();
        RegUnitInfo regUnitInfo = this.getOne(new LambdaQueryWrapper<RegUnitInfo>().eq(RegUnitInfo::getUnitCode, unitCode));
        if(regUnitInfo == null){
            return Boolean.FALSE;
        }
        String companyId = regUnitInfo.getAmosCompanySeq();
        // 1.删除已经创建的 企业信息
        if (StringUtils.isNotEmpty(companyId)) {
            CompanyModel companyModel = Privilege.companyClient.seleteOne(Long.parseLong(companyId)).getResult();
            if (companyModel != null) {
                Privilege.companyClient.deleteCompany(companyId);
            }
        }
        // 2.删除管理员账号
        Privilege.agencyUserClient.multDeleteUser(regUnitInfo.getAdminUserId());
        // 3.企业注册表删除
        this.remove(new LambdaQueryWrapper<RegUnitInfo>().eq(RegUnitInfo::getUnitCode, unitCode));
        // 4.工商信息表删除
        regUnitIcService.remove(new LambdaQueryWrapper<RegUnitIc>().eq(RegUnitIc::getUnitCode, unitCode));
        // 5.许可信息删除
        baseUnitLicenceService.remove(new LambdaQueryWrapper<BaseUnitLicence>().eq(BaseUnitLicence::getUnitCode, unitCode));
        // 6.企业数据信息删除
        tzBaseEnterpriseInfoService.remove(new LambdaQueryWrapper<TzBaseEnterpriseInfo>().eq(TzBaseEnterpriseInfo::getUseCode, unitCode));
        // 7.机场单位表信息删除
        iOrgUsrService.remove(new LambdaQueryWrapper<OrgUsr>().eq(OrgUsr::getAmosOrgId, companyId));
        return Boolean.TRUE;
    }

    private CompanyModel dealChildCompany(CompanyModel cm) {
        cm.setChildren(this.getFilterChild(cm.getChildren()));
        cm.getChildren().stream().filter(n -> {
            CompanyModel c = JSONObject.parseObject(JSON.toJSONString(n), CompanyModel.class);
            return "headquarter".equals(c.getLevel()) || "prefecture-level".equals(c.getLevel()) || "county".equals(c.getLevel());
        }).map(n -> {
            CompanyModel c = JSONObject.parseObject(JSON.toJSONString(n), CompanyModel.class);
            return dealChildCompany(c);
        }).collect(Collectors.toList());
        return cm;
    }

    private List getFilterChild(Collection children) {
        return (List)children.stream().filter(n -> {
            CompanyModel c = JSONObject.parseObject(JSON.toJSONString(n), CompanyModel.class);
            return "headquarter".equals(c.getLevel()) || "prefecture-level".equals(c.getLevel()) || "county".equals(c.getLevel());
        }).map(s->{
            CompanyModel c = JSONObject.parseObject(JSON.toJSONString(s), CompanyModel.class);
            c.setChildren(this.getFilterChild(c.getChildren() != null ? c.getChildren() : new ArrayList()));
            return c;
        }).collect(Collectors.toList());
    }

    private void createCompanyAndUser(RegUnitInfo regUnitInfo) {
        FeignClientResult<List<RoleModel>> roleListResult = Privilege.roleClient.queryRoleList(null, null);
        List<RoleModel> allRoleList = roleListResult.getResult();
        List<RoleModel> userRoleList;
        List<Long> roleIds = new ArrayList<>();
        Set<String> roleNameSet = new HashSet<>();
        // 3.1创建公司
        CompanyModel companyInfo = new CompanyModel();
        companyInfo.setAddress(regUnitInfo.getProvince() + regUnitInfo.getCity() + regUnitInfo.getDistrict() + regUnitInfo.getStree() + regUnitInfo.getCommunity() + regUnitInfo.getAddress());
        companyInfo.setAgencyCode("tzs");
        companyInfo.setParentId(Long.parseLong(regUnitInfo.getManagementUnitId()));
        companyInfo.setLevel("company");
        companyInfo.setCompanyName(regUnitInfo.getName());
        companyInfo.setCompanyCode(regUnitInfo.getUnitCode());
        companyInfo.setContact(regUnitInfo.getLegalPerson());
        companyInfo.setLandlinePhone(regUnitInfo.getLegalPersonTel());
        FeignClientResult<CompanyModel> companyResult = Privilege.companyClient.create(companyInfo);
        if (companyResult == null || companyResult.getResult() == null) {
            throw new BadRequest("单位注册失败");
        }
        String adminUserName = regUnitInfo.getAdminName();
        String loginName = regUnitInfo.getAdminLoginName();
        String pwd = regUnitInfo.getAdminLoginPwd();
        String adminTel = regUnitInfo.getAdminTel();
        // 3.2 创建平台用户
        companyInfo = companyResult.getResult();
        AgencyUserModel agencyUserModel = new AgencyUserModel();
        agencyUserModel.setUserName(loginName);
        agencyUserModel.setRealName(adminUserName);
        agencyUserModel.setLockStatus("UNLOCK");
        agencyUserModel.setPassword(pwd);
        agencyUserModel.setRePassword(pwd);
        agencyUserModel.setAgencyCode("tzs");
        agencyUserModel.setMobile(adminTel);
        String unitTypeCode = regUnitInfo.getUnitTypeCode();
        // 根据unitTypeCode 获取应用和角色 数据字典配置
        DataDictionary unitType = iDataDictionaryService.getOne(new LambdaQueryWrapper<DataDictionary>().eq(DataDictionary::getCode, unitTypeCode));
        String appCode = unitType.getTypeDesc() != null ? unitType.getTypeDesc() : "";
        String[] appCodes = appCode.split(",");
        Set<String> appCodesSet = new HashSet<>();
        Collections.addAll(appCodesSet, appCodes);
        Map<Long, List<Long>> roleSeqMap = new HashMap<>();
        roleNameSet.add(unitType.getName());
        userRoleList = allRoleList.stream().filter(r -> r.getRoleName().equals(unitType.getName())).collect(Collectors.toList());
        userRoleList.forEach(r -> {
            roleIds.add(r.getSequenceNbr());
        });
        roleSeqMap.put(companyInfo.getSequenceNbr(), roleIds);
        Map<Long, List<RoleModel>> orgRoles = new HashMap<>();
        orgRoles.put(companyInfo.getSequenceNbr(), userRoleList);
        agencyUserModel.setAppCodes(new ArrayList<>(appCodesSet));
        agencyUserModel.setOrgRoles(orgRoles);
        agencyUserModel.setOrgRoleSeqs(roleSeqMap);
        FeignClientResult<AgencyUserModel> userResult;
        try {
            userResult = Privilege.agencyUserClient.create(agencyUserModel);
        } catch (InnerInvokException e) {
            // 删除已经创建的 企业信息
            Privilege.companyClient.deleteCompany(companyInfo.getSequenceNbr() + "");
            throw new BadRequest(e.getMessage());
        }

        if (userResult == null || userResult.getResult() == null) {
            throw new BadRequest("注册失败");
        }
        // 3.3 org_user 创建组织机构
        OrgUsr org = new OrgUsr();
        org.setBizOrgCode(TreeParser.genTreeCode());
        org.setBizOrgType(CommonConstant.BIZ_ORG_TYPE_COMPANY);
        org.setBizOrgName(regUnitInfo.getName());
        org.setRecDate(new Date());
        org.setRecUserId(userResult.getResult().getUserId());
        org.setRecUserName(userResult.getResult().getUserName());
        org.setAmosOrgId(companyInfo.getSequenceNbr() + "");
        org.setAmosOrgCode(companyInfo.getOrgCode());
        iOrgUsrService.save(org);
        regUnitInfo.setAdminUserId(userResult.getResult().getUserId());
        regUnitInfo.setAmosCompanySeq(companyInfo.getSequenceNbr().toString());
    }
}