package com.yc.ship.module.ota.service.distributor;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.yc.ship.framework.common.enums.CommonStatusEnum;
import com.yc.ship.framework.common.exception.ServiceException;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.yc.ship.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.yc.ship.framework.security.core.LoginUser;
import com.yc.ship.framework.security.core.util.SecurityFrameworkUtils;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.framework.tenant.core.util.TenantUtils;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.ota.controller.admin.distributor.vo.*;
import com.yc.ship.module.ota.controller.admin.distributorauditlog.vo.DistributorAuditLogSaveReqVO;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.ota.dal.dataobject.distributor.DistributorDO;
import com.yc.ship.module.ota.dal.dataobject.distributortype.DistributorTypeDO;
import com.yc.ship.module.ota.dal.dataobject.otaDistributorRegion.OtaDistributorRegionDO;
import com.yc.ship.module.ota.dal.mysql.distributor.DistributorMapper;
import com.yc.ship.module.ota.dal.mysql.otaDistributorRegion.OtaDistributorRegionMapper;
import com.yc.ship.module.ota.enums.DistributorTypeEnum;
import com.yc.ship.module.ota.service.distributorauditlog.DistributorAuditLogService;
import com.yc.ship.module.ota.service.distributortype.DistributorTypeService;
import com.yc.ship.module.ota.util.OtaAuthUtils;
import com.yc.ship.module.system.api.dept.DeptApi;
import com.yc.ship.module.system.api.dept.dto.DeptReqDTO;
import com.yc.ship.module.system.api.permission.PermissionApi;
import com.yc.ship.module.system.api.user.AdminUserApi;
import com.yc.ship.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.framework.common.pojo.CommonResult.error;
import static com.yc.ship.framework.common.pojo.CommonResult.success;
import static com.yc.ship.module.ota.enums.ErrorCodeConstants.*;


/**
 * 分销商信息 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class DistributorServiceImpl implements DistributorService {

    @Resource
    private  PasswordEncoder passwordEncoder;

    @Resource
    private DistributorMapper distributorMapper;

    @Resource
    private OtaDistributorRegionMapper otaDistributorRegionMapper;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private DeptApi deptApi;

    @Resource
    private PermissionApi permissionApi;

    @Resource
    private OtaAuthUtils otaAuthUtils;

    @Resource
    private ConfigApi configApi;


    @Resource
    private DistributorTypeService distributorTypeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createDistributor(DistributorSaveReqVO createReqVO) {
        // 插入
        DistributorDO distributor = BeanUtils.toBean(createReqVO, DistributorDO.class);
        validateLoginNameUnique(null, createReqVO.getLoginName());
        distributor.setId(IdWorker.getId(distributor));
        distributor.setIsUse(1);
        //分销商是否能够退款审核验证
        if (ObjectUtil.equal(distributor.getType(), DistributorTypeEnum.OTA.getType())) {
            DistributorTypeDO distributorType = distributorTypeService.getDistributorType(distributor.getOtaTypeId());
            Asserts.isTrue(distributorType != null, "分销商类型不存在");
            if (ObjectUtil.equal(distributor.getCanRefundExamine(), 1)) {
                Asserts.isTrue(ObjectUtil.equal(distributorType.getSupportRefundExamine(), 1), "当前分销商类型不支持退款审核，所以不能开启退票审核");
            }
        }

        //登录密码加密
        String password = createReqVO.getPassword();
        if (StringUtils.isNotBlank(password)) {
            password = passwordEncoder.encode(password);
            distributor.setPassword(password);
        }
        List<String> payTypeList = createReqVO.getPayType();
        if (payTypeList != null && !payTypeList.isEmpty()) {
            distributor.setPayType(String.join(",", payTypeList));
        } else {
            distributor.setPayType("");
        }
        List<String> functionList = createReqVO.getFunctions();
        if (functionList != null && !functionList.isEmpty()) {
            distributor.setFunctions(String.join(",", functionList));
        } else {
            distributor.setFunctions("");
        }
        List<String> teamTypeList = createReqVO.getTeamType();
        if (teamTypeList != null && !teamTypeList.isEmpty()) {
            String teamType = String.join(",", teamTypeList);
            distributor.setTeamType(teamType);
        } else {
            distributor.setTeamType("");
        }
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        Long tenantId = loginUser.getTenantId();
        Long userId = createSystemUser(createReqVO, distributor.getId());
        if (createReqVO.getType() == 2) {
            //若为旅行社,则创建新租户
            try {
                if (userId==null) {
                    throw exception(OTA_TENANT_EXISTS);
                } else {
                    //创建分销商默认绑定分销商角色
                    createSystemUserRole(userId, "otc");

                }
            } catch (Exception e) {
                throw exception(DISTRIBUTOR_TENANT_EXISTS);
            }
        } else {
            if (userId==null) {
                throw exception(OTA_TENANT_EXISTS);
            } else {
                //创建分销商默认绑定分销商角色
                createSystemUserRole(userId, "ota");
            }
        }
        distributor.setUserId(userId);
        distributor.setAccountTenantId(tenantId);
        distributorMapper.insert(distributor);
        createDefaultDept(distributor);

        String regionAgency = distributor.getRegionAgency();
        List<OtaDistributorRegionDO> list = new ArrayList<>();
        if (StringUtils.isNotBlank(regionAgency)){
            String[] split = regionAgency.split(",");
            for (String s : split) {
                OtaDistributorRegionDO otaDistributorRegionDO = new OtaDistributorRegionDO();
                otaDistributorRegionDO.setId(IdWorker.getId());
                otaDistributorRegionDO.setDistributorId(distributor.getId());
                otaDistributorRegionDO.setDistributorRegionId(s);
                list.add(otaDistributorRegionDO);
            }
        }
        if(!list.isEmpty()) {
            otaDistributorRegionMapper.insertBatch(list);
        }
        // 返回
        return distributor.getId();
    }

    @Override
    public String createCardNo(Long id) {
        DistributorDO distributorDO = distributorMapper.selectById(id);
        if(distributorDO==null){
            throw exception(DISTRIBUTOR_NOT_EXISTS);
        }
        if(StringUtils.isNotBlank(distributorDO.getCmbShortNo())){
           throw exception(DISTRIBUTOR_SHORT_EXISTS);
        }
        return createChildNo(distributorDO);
    }

    private String createChildNo(DistributorDO distributor) {
        String host = configApi.getPlatformConfigValueByKey("dgConfig_ip");
        String portStr = configApi.getPlatformConfigValueByKey("dgConfig_port");
        String name = configApi.getPlatformConfigValueByKey("dgConfig_name");
        String yqtNo = configApi.getPlatformConfigValueByKey("dgConfig_no");
        String yqtPro = configApi.getPlatformConfigValueByKey("dgConfig_pro");
        String yqtCard = configApi.getPlatformConfigValueByKey("dgConfig_card");

//        String host = "10.1.10.105";
        int port = 15999;
        if(StringUtils.isNotBlank(portStr)){
            try {
                port = Integer.parseInt(portStr);
            }catch (Exception ignored){

            }
        }
//        String name = "宜畅式东士煌本孔凰于慊官送";
        Random random = new Random();
        int randomNumber = random.nextInt(90000) + 10000;
        String cardNo = distributor.getUserId().toString()+""+randomNumber;
        try {
            // 1. 获取当前时间，用于组装公共包头流水与日期
            Date now = new Date();
            String reqDate = new SimpleDateFormat("yyyyMMdd").format(now);
            String reqTime = new SimpleDateFormat("HHmmss").format(now);
            // 构造请求方流水号 (保证唯一性)
            int randomNumber2 = random.nextInt(1000) + 1000;
            String reqSeqNo = new SimpleDateFormat("yyyyMMddHHmmss").format(now) + ""+randomNumber2+"";
            // 2. 构造 CMLT40 增加多级账簿 XML 请求报文
            String xmlData = "<ap>\n" +
                    "  <CCTransCode>CMLT40</CCTransCode>\n" +
                    "  <ProductID>ICC</ProductID>\n" +
                    "  <ChannelType>ERP</ChannelType>\n" +
                    "  <CorpNo>"+yqtNo+"</CorpNo>\n" +
                    "  <OpNo></OpNo>\n" +
                    "  <AuthNo></AuthNo>\n" +
                    "  <ReqSeqNo>" + reqSeqNo + "</ReqSeqNo>\n" +
                    "  <ReqDate>" + reqDate + "</ReqDate>\n" +
                    "  <ReqTime>" + reqTime + "</ReqTime>\n" +
                    "  <Sign></Sign>\n" +
                    "  <Corp>\n" +
                    "    <DbLogAccName>"+name+distributor.getName()+"</DbLogAccName>\n" +
                    "    <IntTyp>0</IntTyp>\n" +
                    "    <DbIntType>F</DbIntType>\n" +
                    "    <DbRit>0.00</DbRit>\n" +
                    "    <DbAddType>1</DbAddType>\n" +
                    "    <DbRatType>00002000</DbRatType>\n" +
                    "    <DbRatPct>0.00</DbRatPct>\n" +
                    "    <DbRatAdd>0.00</DbRatAdd>\n" +
                    "    <CrIntType>F</CrIntType>\n" +
                    "    <CrRit>0.00</CrRit>\n" +
                    "    <CrAddType>1</CrAddType>\n" +
                    "    <CrRatType>00002000</CrRatType>\n" +
                    "    <CrRatPct>0.00</CrRatPct>\n" +
                    "    <CrRatAdd>0.00</CrRatAdd>\n" +
                    "    <PmtHd>01</PmtHd>\n" +
                    "    <ActInf>0</ActInf>\n" +
                    "  </Corp>\n" +
                    "  <Cmp>\n" +
                    "    <DbProv>"+yqtPro+"</DbProv>\n" +
                    "    <DbAccNo>"+yqtCard+"</DbAccNo>\n" +
                    "    <DbLogAccNo>"+cardNo+"</DbLogAccNo>\n" +
                    "    <DbCur>01</DbCur>\n" +
                    "    <CrLogAccNo>0000000000</CrLogAccNo>\n" +
                    "    <LogAccBkOInd>0</LogAccBkOInd>\n" +
                    "  </Cmp>\n" +
                    "</ap>";

            // 3. 按照约定编码报文 (ERP上送报文必须为GBK字符集)
            byte[] xmlBytes = xmlData.getBytes("GBK");

            // 4. 构造7字节包头
            // 第1字节为加密标志（0-不加密），后6字节为数据包长度（包含加密标志位），不足6位在右边用空格补足
//            int packetLen = xmlBytes.length + 1;
            int packetLen = xmlBytes.length;
            String lengthStr = String.format("%-6s", packetLen);
            String headerStr = "0" + lengthStr;
            byte[] headerBytes = headerStr.getBytes("GBK");

            // 拼接完整的待发送字节数组
            byte[] fullPacket = new byte[headerBytes.length + xmlBytes.length];
            System.arraycopy(headerBytes, 0, fullPacket, 0, headerBytes.length);
            System.arraycopy(xmlBytes, 0, fullPacket, headerBytes.length, xmlBytes.length);

            // 5. 发送 TCP/IP Socket 同步短连接请求
            System.out.println("正在连接到前置机 " + host + ":" + port + "...");
            Socket socket = new Socket(host, port);
            // 设置读取超时时间为 30 秒
//            socket.setSoTimeout(30000);

            OutputStream out = socket.getOutputStream();
            out.write(fullPacket);
            out.flush();
            System.out.println("请求报文发送成功，等待响应...\n");
            System.out.println("请求报文发送成功，等待响应...\n"+new String(fullPacket, "GBK"));

//            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
//            PrintWriter out2 = new PrintWriter(socket.getOutputStream(), true);
//
//            String inputLine;
//            while ((inputLine = in.readLine()) != null) {
//                System.out.println("Received: " + inputLine);
//                out2.println("Echo: " + inputLine); // 回显客户端发送的数据
//            }

            // 6. 接收并解析前置机返回的报文
            InputStream in = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;
            // 使用 StringBuilder 拼接读取到的报文内容，必须以 GBK 解码
            StringBuilder responseBuilder = new StringBuilder();

            while ((bytesRead = in.read(buffer)) != -1) {
                responseBuilder.append(new String(buffer, 0, bytesRead, "GBK"));
            }

            socket.close();
            in.close();
            out.close();

            String recvData = responseBuilder.toString();
            if (recvData.length() >= 7) {
                String respHeader = recvData.substring(0, 7);
                String respXml = recvData.substring(7);
                System.out.println("收到前置机响应头: '" + respHeader + "'");
                System.out.println("收到前置机响应报文:\n" + respXml);
                JSONObject jsonObject = XML.toJSONObject(respXml);
                System.out.println(jsonObject);

                JSONObject ap = jsonObject.getJSONObject("ap");
                String respCode = ap.getStr("RespCode");
                if(!"0000".equals(respCode)){
                    System.err.println("交易发送异常，异常信息："+ap.getStr("RespInfo"));
                    return "创建子账薄失败："+ap.getStr("RespInfo");
                }else {
                    String resultCode = ap.getJSONObject("Cmp").getStr("DbLogAccNo");
                    System.err.println("卡号：" + resultCode);
                    distributorMapper.updateShortCode(distributor.getId(),resultCode);
                    return "创建子账薄成功："+resultCode;
                }
            } else {
                System.out.println("响应报文异常或为空");
                return "创建子账薄失败：响应报文异常或为空";
            }

        } catch (SocketTimeoutException e) {
            System.err.println("交易发送超时，请检查ICT前置机通讯状态。");
            return "创建子账薄失败：交易发送超时";
        } catch (Exception e) {
            System.err.println("交易发送异常: " + e.getMessage());
            e.printStackTrace();
            return "创建子账薄失败："+e.getMessage();
        }
    }

    @Override
    public DistributorImportRespVO importDistributorList(List<DistributorImportExcelVO> distributorImportExcelVOS) {
        for (DistributorImportExcelVO distributorImportExcelVO : distributorImportExcelVOS) {
            DistributorSaveReqVO distributor = BeanUtils.toBean(distributorImportExcelVO, DistributorSaveReqVO.class);
            distributor.setType(2);
            distributor.setPassword("111111");
            distributor.setSelfSupport(0);
            distributor.setSelfSupport(0);
            distributor.setLoginName(distributorImportExcelVO.getUserName());
            try {
                createDistributor(distributor);
                System.out.println("分销商："+distributor.getName()+"创建成功");
            }catch (Exception e){
                System.out.println("分销商："+distributor.getName()+"创建失败");
            }
        }
        return DistributorImportRespVO.builder().createSuppliers(new ArrayList<>())
                .updateSuppliers(new ArrayList<>()).failureSuppliers(new LinkedHashMap<>()).build();
    }

    @Override
    public void updateDistributor(DistributorSaveReqVO updateReqVO) {
        // 校验存在
        validateDistributorExists(updateReqVO.getId());
        // 校验登录名重复
        validateLoginNameUnique(updateReqVO.getId(), updateReqVO.getLoginName());
        // 更新
        DistributorDO updateObj = BeanUtils.toBean(updateReqVO, DistributorDO.class);
        //分销商是否能够退款审核验证
        if (ObjectUtil.equal(updateObj.getType(), DistributorTypeEnum.OTA.getType())) {
            DistributorTypeDO distributorType = distributorTypeService.getDistributorType(updateObj.getOtaTypeId());
            Asserts.isTrue(distributorType != null, "分销商类型不存在");
            if (ObjectUtil.equal(updateObj.getCanRefundExamine(), 1)) {
                Asserts.isTrue(ObjectUtil.equal(distributorType.getSupportRefundExamine(), 1), "当前分销商类型不支持退款审核，所以不能开启退票审核");
            }
        }
        //登录密码加密
        String password = updateReqVO.getPassword();
        if (StringUtils.isNotBlank(password)) {
            password = passwordEncoder.encode(password);
            updateObj.setPassword(password);
        }
        List<String> payTypeList = updateReqVO.getPayType();
        if (payTypeList != null && !payTypeList.isEmpty()) {
            String payType = String.join(",", payTypeList);
            updateObj.setPayType(payType);
        } else {
            updateObj.setPayType("");
        }
        List<String> functionList = updateReqVO.getFunctions();
        if (functionList != null && !functionList.isEmpty()) {
            String functions = String.join(",", functionList);
            updateObj.setFunctions(functions);
        } else {
            updateObj.setFunctions("");
        }
        List<String> teamTypeList = updateReqVO.getTeamType();
        if (teamTypeList != null && !teamTypeList.isEmpty()) {
            String teamType = String.join(",", teamTypeList);
            updateObj.setTeamType(teamType);
        } else {
            updateObj.setTeamType("");
        }
        //修改信息
        distributorMapper.updateById(updateObj);

        otaDistributorRegionMapper.delete(new QueryWrapper<OtaDistributorRegionDO>().eq("distributor_id", updateObj.getId()));
        String regionAgency = updateObj.getRegionAgency();
        List<OtaDistributorRegionDO> list = new ArrayList<>();
        if (StringUtils.isNotBlank(regionAgency)){
            String[] split = regionAgency.split(",");
            for (String s : split) {
                OtaDistributorRegionDO otaDistributorRegionDO = new OtaDistributorRegionDO();
                otaDistributorRegionDO.setId(IdWorker.getId());
                otaDistributorRegionDO.setDistributorId(updateObj.getId());
                otaDistributorRegionDO.setDistributorRegionId(s);
                list.add(otaDistributorRegionDO);
            }
        }
        if(!list.isEmpty()) {
            otaDistributorRegionMapper.insertBatch(list);
        }

    }

    @Override
    public void updatePassword(DistributorUpdatePasswordReqVO updateReqVO) {
        // 校验存在
        validateDistributorExists(updateReqVO.getId());
        // 更新
        DistributorDO updateObj = new DistributorDO();
        updateObj.setId(updateReqVO.getId());
        //登录密码加密
        String password = updateReqVO.getPassword();
        if (StringUtils.isNotBlank(password)) {
            password = passwordEncoder.encode(password);
            updateObj.setPassword(password);
        }
        DistributorRespVO distributorRespVO = distributorMapper.getById(updateReqVO.getId());
        updateObj.setLoginName(distributorRespVO.getLoginName());
        updateReqVO.setTenantId(distributorRespVO.getAccountTenantId());
        //修改后台用户密码
        updateSystemUserPassword(updateReqVO);
        distributorMapper.updateById(updateObj);
    }

    @Override
    public void deleteDistributor(Long id) {
        // 校验存在
        validateDistributorExists(id);
        DistributorDO distributorDO = distributorMapper.selectById(id);
        if (distributorDO.getType() == 2) {
            adminUserApi.deleteUser(distributorDO.getLoginName());
        }
        // 删除
        distributorMapper.deleteById(id);
    }

    private void validateDistributorExists(Long id) {
        if (distributorMapper.selectById(id) == null) {
            throw exception(DISTRIBUTOR_NOT_EXISTS);
        }
    }

    @Override
    @TenantIgnore
    public DistributorDO getDistributor(Long id) {
        return distributorMapper.selectById(id);
    }

    @Override
    @TenantIgnore
    public DistributorDO getDistributorNew(Long id) {
        DistributorDO distributor = distributorMapper.selectById(id);
        if(distributor == null){
            distributor = distributorMapper.getDistributorNew(id);
        }
        return distributor;
    }

    @Override
    @TenantIgnore
    public DistributorDO getDistributorByName(String name) {
        return distributorMapper.selectOne(DistributorDO::getLoginName, name);
    }

    @Override
    public PageResult<DistributorDO> getDistributorPage(DistributorPageReqVO pageReqVO) {
        return distributorMapper.selectPage(pageReqVO);
    }

    @Override
    public List<DistributorDO> getSimpleList(DistributorListReqVO reqVO) {
        LoginUser loginUser = otaAuthUtils.getAgencyLoginUser();
        if(loginUser != null) {
            //是否旅行社登录
            Long distributorId = loginUser.getDistributorId();
            if(distributorId != null) {
                DistributorRespVO distributor = distributorMapper.getDistributorById(distributorId);
                DistributorDO distributorDO = BeanUtils.toBean(distributor, DistributorDO.class);
                return Collections.singletonList(distributorDO);
            }
        }
        return distributorMapper.getSimpleList(reqVO);
    }


    @Override
    public void updateStatus(Long id, Integer status) {
        // 校验存在
        validateDistributorExists(id);
        // 更新状态
        DistributorDO updateObj = new DistributorDO();
        updateObj.setId(id);
        updateObj.setIsUse(status);
        distributorMapper.updateById(updateObj);

        //同步更新用户状态
        DistributorRespVO distributor = distributorMapper.getById(id);
        if(distributor != null){
            if(status == 1){
                status = 0;
            }else if(status ==0){
                status = 1;
            }
            adminUserApi.updateStatus(distributor.getLoginName(), status);
        }

    }

    @Override
    public List<Map> getOtcSimpleList(DistributorSaveReqVO params) {
        return distributorMapper.getOtcSimpleList(params);
    }

    @Override
    public boolean addBalance(Long id, BigDecimal money) {
        int res = distributorMapper.addBalance(id, money);
        return res > 0;
    }

    @Override
    public boolean subSurplus(Long id, BigDecimal money) {
        int count = distributorMapper.subSurplus(id, money);
        return count > 0;
    }

    @Override
    public boolean subPayCredit(Long id, BigDecimal money) {
        int count = distributorMapper.subPayCredit(id, money);
        return count > 0;
    }


    @Override
    public boolean addPayCredit(Long id, BigDecimal money) {
        int count = distributorMapper.addPayCredit(id, money);
        return count > 0;
    }

    @Override
    public boolean addInventory(Long id, BigDecimal money) {
        int res = distributorMapper.addInventory(id, money);
        return res > 0;
    }

    void validateLoginNameUnique(Long id, String loginName) {
        if (StrUtil.isBlank(loginName)) {
            return;
        }
        DistributorDO user = distributorMapper.selectByLoginName(loginName);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(DISTRIBUTOR_LOGINNAME_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(DISTRIBUTOR_LOGINNAME_EXISTS);
        }
    }


    Long createSystemUser(DistributorSaveReqVO createReqVO, Long distributorId) {
        AdminUserRespDTO reqDTO = new AdminUserRespDTO();
        reqDTO.setUsername(createReqVO.getLoginName());
        reqDTO.setPassword(createReqVO.getPassword());
        reqDTO.setNickname(createReqVO.getName());
        reqDTO.setMobile(createReqVO.getPhone());
        reqDTO.setDistributorId(distributorId);
        return adminUserApi.createUser(reqDTO);
    }

    /**
     * 创建默认部门
     */
    private void createDefaultDept(DistributorDO distributor) {
        DeptReqDTO reqDTO = new DeptReqDTO();
        reqDTO.setName(distributor.getName());
        reqDTO.setSort(0);
        reqDTO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        reqDTO.setLeaderUserId(distributor.getUserId());
        deptApi.createDept(reqDTO);

    }

    //OTA用户默认绑定角色
    void createSystemUserRole(Long userId, String code) {
        permissionApi.savePermissions(userId, code);
    }

    void updateSystemUserPassword(DistributorUpdatePasswordReqVO updateReqVO) {
        adminUserApi.updatePwd(updateReqVO.getLoginName(),updateReqVO.getPassword());
    }

    @Override
    @TenantIgnore
    public CommonResult<DistributorRespDTO> getDistributorByAccountTenantId(Long accountTenantId) {
        List<DistributorDO> distributor = distributorMapper.selectList(DistributorDO::getAccountTenantId, accountTenantId);
        if(distributor!=null && !distributor.isEmpty()){
            return success(BeanUtils.toBean(distributor.get(0), DistributorRespDTO.class));
        }else{
            return error(500,"未查询到分销商信息");
        }

    }

    @Override
    public List<DistributorRespVO> getOtcDistributor(Integer type) {
        LoginUser loginUser = otaAuthUtils.getAgencyLoginUser();
        Long distributorId = loginUser.getDistributorId();
        if(distributorId == null){
            return distributorMapper.getOtcDistributor(type);
        }else{
            return distributorMapper.getOtcDistributorByOtaId(type,distributorId);
        }
    }

    @Override
    public List<DistributorDO> selectListByType(Integer type) {
        return distributorMapper.selectListByType(type);
    }

    @Override
    public List<DistributorDO> selectChildNo() {
        return distributorMapper.selectChildNo();
    }

    @Override
    public List<DistributorRespVO> getOtcDistributor(Integer type, Long productId) {
        return distributorMapper.getOtcDistributorWithId(type, productId);
    }

    @Override
    public boolean subBalance(Long distributorId, BigDecimal money) {
        int count = distributorMapper.subBalance(distributorId, money);
        return count > 0;
    }

    @Override
    public boolean addSurplus(Long distributorId, BigDecimal money) {
        int count = distributorMapper.addSurplus(distributorId, money);
        return count > 0;
    }

    @Override
    public boolean subInventory(Long distributorId, BigDecimal money) {
        int count = distributorMapper.subInventory(distributorId, money);
        return count > 0;
    }

    @Override
    public CommonResult<DistributorRespDTO> getDistributorByOtaAccount(String otaAccount, String typeCode) {
        List<DistributorDO> distributorDOList = distributorMapper.getDistributorByOtaAccountAndType(otaAccount, typeCode);
        DistributorRespDTO respDto = null;
        if (CollectionUtil.isNotEmpty(distributorDOList)) {
            respDto = BeanUtils.toBean(distributorDOList.get(0), DistributorRespDTO.class);
        }
        return success(respDto);
    }

    @Override
    public DistributorDO getDistributorById(Long distributorId) {
        MPJLambdaWrapper<DistributorDO> wrapper = new MPJLambdaWrapperX<DistributorDO>()
                .selectAll(DistributorDO.class)
                .selectAs(DistributorTypeDO::getTypeCode, DistributorDO::getTypeCode)
                .leftJoin(DistributorTypeDO.class, DistributorTypeDO::getId, DistributorDO::getOtaTypeId)
                .eq(DistributorDO::getId, distributorId);
        return distributorMapper.selectJoinOne(DistributorDO.class, wrapper);
    }

    @Override
    public DistributorDO getDistributorByLoginUser(String loginName) {
        LambdaQueryWrapperX<DistributorDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(DistributorDO::getLoginName, loginName);
        DistributorDO distributorDO = distributorMapper.selectOne(queryWrapper);
        return distributorDO;
    }

    @Resource
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long updateDistributorCard(Long distributorId, Integer mode, BigDecimal amount, Long userId, Long orderId, Long refundId) {
        String key = "ota_" + distributorId;
        RLock lock = redissonClient.getLock(key);
        BigDecimal beforeBigDecimal;
        BigDecimal afterBigDecimal;
        try {
            Long logId;
            DistributorDO distributorDO;
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                try {
                    distributorDO = getDistributor(distributorId);
                    Assert.notNull(distributorDO, "分销商不存在！");
                    if (!distributorDO.getPayType().contains("2")) {
                        throw exception(DISTRIBUTOR_REQUEST_NOT_ENABLE);
                    }
                    // 额度变更流水
                    beforeBigDecimal = distributorDO.getPayCredit();
                    if (mode == 1) {
                        // 增加
                        afterBigDecimal = beforeBigDecimal.add(amount);
                    } else {
                        // 减少
                        afterBigDecimal = beforeBigDecimal.subtract(amount);
                        if (afterBigDecimal.compareTo(BigDecimal.ZERO) < 0) {
                            throw exception(DISTRIBUTOR_REQUEST_CREDIT);
                        }
                    }
                    distributorDO.setPayCredit(afterBigDecimal);
                    UpdateWrapper<DistributorDO> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.eq("id", distributorDO.getId());
                    updateWrapper.set("pay_credit", afterBigDecimal);
                    distributorMapper.update(updateWrapper);
                    logId = saveLog(distributorDO, mode, beforeBigDecimal, afterBigDecimal, amount, userId, orderId, refundId);
                } finally {
                    if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
                return logId;
            } else {
                throw exception(DISTRIBUTOR_REQUEST_TIMEOUT);
            }
        } catch (Exception e) {
            if(e instanceof ServiceException) {
                throw (ServiceException) e;
            }
            log.error("授信异常",e);
            throw exception(DISTRIBUTOR_REQUEST_FAIL);
        }
    }

    @Override
    public List<DistributorDO> getDistributorList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return distributorMapper.selectBatchIds(ids);
    }

    @Override
    public List<DistributorDO> getDistributorsByAccountTenantId(Long accountTenantId) {
        return distributorMapper.selectList(DistributorDO::getAccountTenantId, accountTenantId);
    }

    @Override
    public LoginTypeRespVO getLoginType() {
        AtomicReference<LoginTypeRespVO> loginType = new AtomicReference<>();
        LoginUser loginUser = otaAuthUtils.getAgencyLoginUser();
        TenantUtils.executeIgnore(() -> {
            LoginTypeRespVO typeRespVO = null;
            DistributorDO distributorDO = getDistributorById(loginUser.getDistributorId());
            if (distributorDO!=null) {
                // 旅行社端
                typeRespVO = new LoginTypeRespVO();
                typeRespVO.setType(1);
                typeRespVO.setDistributorId(distributorDO.getId());
                typeRespVO.setAccountTenantId(distributorDO.getAccountTenantId());
                typeRespVO.setTenantId(distributorDO.getTenantId());
                typeRespVO.setDistributorName(distributorDO.getName());
            }
            loginType.set(typeRespVO);
        });
        if (loginType.get() != null) {
            return loginType.get();
        }
        LoginTypeRespVO typeRespVO = new LoginTypeRespVO();
        typeRespVO.setType(3);
        return typeRespVO;
    }

    @Override
    public DistributorRespVO queryDistributorMoneyTotal(Long distributorId) {
        return distributorMapper.queryDistributorMoneyTotal(distributorId);
    }

    @Override
    public DistributorDO getDistributorByLoginUserId(Long loginUserId) {
        return distributorMapper.selectByUserId(loginUserId);
    }

    @Resource
    private DistributorAuditLogService distributorAuditLogService;

    private Long saveLog(DistributorDO distributor, Integer mode, BigDecimal beforeBigDecimal, BigDecimal afterBigDecimal, BigDecimal amount, Long userId, Long orderId, Long refundId) {
        // 授信额度变更
        DistributorAuditLogSaveReqVO saveReqVO = new DistributorAuditLogSaveReqVO();
        saveReqVO.setDistributorId(distributor.getId());
        saveReqVO.setBeforeCredit(beforeBigDecimal);
        saveReqVO.setAfterCredit(afterBigDecimal);
        saveReqVO.setCreditAmount(amount);
        saveReqVO.setUserId(userId + "");
        saveReqVO.setTenantId(distributor.getTenantId());
        saveReqVO.setCreditMode(mode);
        String remark;
        if (mode == 1) {
            remark = "提额申请通过！额度提升" + amount.setScale(2) + "元，提升后授信额度为" + afterBigDecimal.setScale(2);
        } else {
            remark = "降额申请通过！额度降低" + amount.setScale(2) + "元，降低后授信额度为" + afterBigDecimal.setScale(2);
        }
        saveReqVO.setRemark(remark);
        return distributorAuditLogService.createDistributorAuditLog(saveReqVO);
    }

    @Override
    public DistributorRespVO getADistributorById(Long id){
        return distributorMapper.getDistributorById(id);
    }
}
