package org.dromara.payment.sys.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.enums.BusRole;
import org.dromara.common.core.enums.SmsType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.payment.common.domain.BusAccounts;
import org.dromara.payment.common.mapper.BusAccountsMapper;
import org.dromara.payment.properties.PayPasswordProperties;
import org.dromara.payment.properties.PlatformProperties;
import org.dromara.payment.sys.domain.*;
import org.dromara.payment.sys.domain.vo.SelectSydVo;
import org.dromara.payment.sys.mapper.*;
import org.dromara.payment.sys.domain.vo.SysSydVo;
import org.dromara.resource.api.RemoteJzqService;
import org.dromara.resource.api.RemoteSmsService;
import org.dromara.settlement.api.RemoteAccountService;
import org.dromara.settlement.api.domain.Account;
import org.dromara.settlement.api.domain.Result;
import org.dromara.settlement.api.domain.SignZhifubao;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.bo.RemoteUserBo;
import org.dromara.system.api.domain.vo.RemoteSysUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dromara.payment.sys.domain.bo.SysSydBo;
import org.dromara.payment.sys.service.ISysSydService;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.function.Function;

/**
 * 服务商Service业务层处理
 *
 * @author LionLi
 * @date 2024-03-26
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class SysSydServiceImpl implements ISysSydService {

    private final SysSydMapper baseMapper;

    private final SysSydLogMapper sydLogMapper;

    private final SysUnitMapper sysUnitMapper;

    private final BusAccountsMapper accountsMapper;

    private final SysSydServiceTransactionImpl transactionImpl;

    private final BankAccountServiceTransactionImpl bankAccountTransactionImpl;

    private final SysSydConfigMapper sysSydConfigMapper;
    @DubboReference
    private RemoteAccountService accountService;//银行账户

    private final SysSydSignContentMapper signContentDao;//结算中心协议dao

    private final SysSydAccountMapper sysSydAccountMapper;

    @DubboReference
    private RemoteSmsService remoteSmsService;

    @DubboReference
    private RemoteJzqService remoteJzqService;

    @Autowired
    private PlatformProperties platformProperties;

    @DubboReference
    private RemoteUserService remoteUserService;

    /**
     * 查询服务商
     */
    @Override
    public SysSydVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询服务商列表
     */
    @Override
    public TableDataInfo<SysSydVo> queryPageList(SysSydBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysSyd> lqw = buildQueryWrapper(bo);
        Page<SysSydVo> result = baseMapper.selectSydList(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询服务商列表
     */
    @Override
    public List<SysSydVo> queryList(SysSydBo bo) {
        LambdaQueryWrapper<SysSyd> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysSyd> buildQueryWrapper(SysSydBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysSyd> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getNo()), SysSyd::getNo, bo.getNo());
        lqw.eq(StringUtils.isNotBlank(bo.getGsmc()), SysSyd::getGsmc, bo.getGsmc());
        lqw.eq(StringUtils.isNotBlank(bo.getKfd()), SysSyd::getKfd, bo.getKfd());
        lqw.eq(StringUtils.isNotBlank(bo.getKfh()), SysSyd::getKfh, bo.getKfh());
        lqw.eq(StringUtils.isNotBlank(bo.getKhhNo()), SysSyd::getKhhNo, bo.getKhhNo());
        lqw.eq(bo.getBankType() != null, SysSyd::getBankType, bo.getBankType());
        lqw.eq(StringUtils.isNotBlank(bo.getBankCard()), SysSyd::getBankCard, bo.getBankCard());
        lqw.eq(bo.getJbsl() != null, SysSyd::getJbsl, bo.getJbsl());
        lqw.eq(bo.getQuoteNum() != null, SysSyd::getQuoteNum, bo.getQuoteNum());
        lqw.eq(bo.getAddTime() != null, SysSyd::getAddTime, bo.getAddTime());
        lqw.eq(StringUtils.isNotBlank(bo.getAddBy()), SysSyd::getAddBy, bo.getAddBy());
        lqw.eq(StringUtils.isNotBlank(bo.getEditer()), SysSyd::getEditer, bo.getEditer());
        lqw.eq(bo.getEditTime() != null, SysSyd::getEditTime, bo.getEditTime());
        lqw.eq(bo.getProvinceId() != null, SysSyd::getProvinceId, bo.getProvinceId());
        lqw.like(StringUtils.isNotBlank(bo.getProvinceName()), SysSyd::getProvinceName, bo.getProvinceName());
        lqw.eq(bo.getCityId() != null, SysSyd::getCityId, bo.getCityId());
        lqw.like(StringUtils.isNotBlank(bo.getCityName()), SysSyd::getCityName, bo.getCityName());
        lqw.eq(bo.getCountyId() != null, SysSyd::getCountyId, bo.getCountyId());
        lqw.like(StringUtils.isNotBlank(bo.getCountyName()), SysSyd::getCountyName, bo.getCountyName());
        lqw.eq(StringUtils.isNotBlank(bo.getNsrSbh()), SysSyd::getNsrSbh, bo.getNsrSbh());
        lqw.eq(StringUtils.isNotBlank(bo.getFr()), SysSyd::getFr, bo.getFr());
        lqw.eq(StringUtils.isNotBlank(bo.getFrCardid()), SysSyd::getFrCardid, bo.getFrCardid());
        lqw.eq(StringUtils.isNotBlank(bo.getFrPhone()), SysSyd::getFrPhone, bo.getFrPhone());
        lqw.like(StringUtils.isNotBlank(bo.getConName()), SysSyd::getConName, bo.getConName());
        lqw.eq(StringUtils.isNotBlank(bo.getConPhone()), SysSyd::getConPhone, bo.getConPhone());
        lqw.eq(StringUtils.isNotBlank(bo.getConCardid()), SysSyd::getConCardid, bo.getConCardid());
        lqw.eq(StringUtils.isNotBlank(bo.getConEmail()), SysSyd::getConEmail, bo.getConEmail());
        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysSyd::getAddress, bo.getAddress());
        lqw.eq(StringUtils.isNotBlank(bo.getBusiness()), SysSyd::getBusiness, bo.getBusiness());
        lqw.eq(StringUtils.isNotBlank(bo.getAbridge()), SysSyd::getAbridge, bo.getAbridge());
        lqw.eq(StringUtils.isNotBlank(bo.getPayPassword()), SysSyd::getPayPassword, bo.getPayPassword());
        lqw.eq(bo.getPassErrorNum() != null, SysSyd::getPassErrorNum, bo.getPassErrorNum());
        lqw.eq(bo.getPassFrozenTime() != null, SysSyd::getPassFrozenTime, bo.getPassFrozenTime());
        lqw.orderByDesc(SysSyd::getAddTime);
        return lqw;
    }




    /**
     * 新增服务商
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean  insertByBo(SysSydBo bo) throws Exception {

        String email = bo.getConEmail();
        String name = bo.getConName();
        Integer organizationType = 0;
        Integer identificationType = 1;
        String organizationRegNo = bo.getNsrSbh();
        String saveDir = "/www/wwwroot";
        // 保存的文件名
        String fileName = "downloaded_image.jpeg";
        File organizationRegImg = createFileFromURL(bo.getYyzz(), saveDir, fileName);



        String legalName = bo.getFr();
        String legalIdentityCard = bo.getFrCardid();
        String legalMobile = bo.getFrPhone();

        String s = remoteJzqService.organizationCreate(email, name, organizationType, identificationType, organizationRegNo,
            organizationRegImg, legalName, legalIdentityCard, legalMobile);

        JSONObject parse = JSONObject.parseObject(s);
        if (parse.getString("success").equals("false")) {
            throw new ServiceException(parse.getString("msg"));
        }

        SysSyd add = MapstructUtils.convert(bo, SysSyd.class);
        validEntityBeforeSave(add);
        String no = genNo(0,10);
        SysUnit sysUnit = new SysUnit();
        sysUnit.setNo(no);
        sysUnit.setId(IdUtil.getSnowflakeNextId());
        sysUnit.setUnitType(BusRole.SERVICE.getId());
        sysUnit.setName(add.getGsmc());
        sysUnit.setCustNo(no.substring(1));
        sysUnitMapper.insert(sysUnit);
        add.setId(sysUnit.getId());
        add.setNo(no);
        add.setAddBy(bo.getAddBy());
        add.setAddTime(new Date());
        add.setEditer(bo.getAddBy());
        add.setEditTime(bo.getAddTime());
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }

        SysSydConfig   sysSydConfig = new SysSydConfig();
        sysSydConfig.setSydId(add.getId());
        sysSydConfig.setAutoApprove(1);
        sysSydConfig.setCreateTime(new Date());
        sysSydConfig.setCreateBy(LoginHelper.getUserId());
        sysSydConfigMapper.insert(sysSydConfig);



        RemoteUserBo remoteUserBo = new RemoteUserBo();
        remoteUserBo.setBusId(bo.getId());
        remoteUserBo.setBusNo(add.getNo());
        remoteUserBo.setRoleId(BusRole.SERVICE.getId());
        remoteUserBo.setRoleName(BusRole.SERVICE.getName());
        remoteUserBo.setRoleDataRange(1);
        remoteUserBo.setNickName(bo.getGsmc());
        remoteUserBo.setCreateTime(new Date());
        remoteUserBo.setPhonenumber(bo.getConPhone());
        remoteUserBo.setCreateBy(LoginHelper.getUserId());
        remoteUserBo.setUserName("S"+StringUtils.randmNumber(5));
        String pwd = StringUtils.randmNumber(6);
        remoteUserBo.setPassword(BCrypt.hashpw(pwd));
        this.addUser(remoteUserBo);

        LinkedHashMap smsMap = new LinkedHashMap();
        smsMap.put("type",BusRole.SERVICE.getName());
        smsMap.put("name",remoteUserBo.getUserName());
        smsMap.put("pwd",pwd);
        this.remoteSmsService.send(bo.getDomain(),remoteUserBo.getPhonenumber(), SmsType.UNIT_OPEN,smsMap);

        return flag;
    }


    public static File createFileFromURL(String fileUrl, String saveDir, String fileName) throws Exception {
        // 确保保存目录存在
        File savePath = new File(saveDir);
        if (!savePath.exists()) {
            savePath.mkdirs();
        }

        // 创建目标文件
        File file = new File(saveDir, fileName);

        // 从URL下载文件并保存到本地
        try (InputStream inputStream = new URL(fileUrl).openStream();
             FileOutputStream outputStream = new FileOutputStream(file)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        return file;
    }

    private void addUser(RemoteUserBo remoteUserBo){
        int result = this.remoteUserService.insertBusUser(remoteUserBo);
        if(result  == -1){
            remoteUserBo.setUserName("S"+StringUtils.randmNumber(5));
            this.addUser(remoteUserBo);
        }

    }

    /**
     * 生成服务商编号
     * @param retry 当前重试次数
     * @param maxRetry 最大重试次数
     * @return
     */
    public String genNo(int retry,int maxRetry){
        String no = "S"+ RandomUtil.randomNumbers(5);
        LambdaQueryWrapper<SysSyd> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysSyd::getNo,no);
        SysSyd exists = baseMapper.selectOne(lqw);
        if(exists != null){
            if(retry > maxRetry){
                throw new ServiceException("服务商编号生成出错");
            }else {
                no = genNo(retry + 1,maxRetry);
            }
        }
        return no;
    }

    /**
     * 修改服务商
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(SysSydBo bo) {
        SysSyd update = MapstructUtils.convert(bo, SysSyd.class);
        validEntityBeforeSave(update);
        update.setEditer(bo.getEditer());
        update.setEditTime(new Date());
        sysUnitMapper.update(new LambdaUpdateWrapper<SysUnit>()
                .set(SysUnit::getName, update.getGsmc())
                .eq(SysUnit::getId, update.getId()));
        sydLogMapper.insertSysSydLog(update.getId(),new Date());
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysSyd entity){
        //TODO 做一些数据校验,如唯一约束
        LambdaQueryWrapper<SysSyd> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysSyd::getGsmc,entity.getGsmc());
        SysSyd exists = baseMapper.selectOne(lqw);
        if(exists != null && (entity.getId() == null || !entity.getId().equals(exists.getId()))){
            throw new ServiceException("服务商已存在");
        }
    }

    /**
     * 批量删除服务商
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        sysUnitMapper.deleteBatchIds(ids);
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public Boolean creatSydXNnum(Long id, String gsmc) {
        //服务商账户
        Map paraMap= new HashMap();

        paraMap.put("sydId",id);
        paraMap.put("accType",0);
        paraMap.put("bankType",id);


        Boolean sydRtn = creatXNnum(id,id,gsmc,BusRole.SERVICE.getId(),BusRole.PLATFORM.getId(), add -> {
            if(add != null) {
                if(add.getId() > 0) {
                    Integer num = sysSydAccountMapper.insertSysSydAccount(new SysSydAccount(null, add.getUnitId(), add.getAccId(), 0, add.getBankType(), add.getBankCard(), 0l, 0l, (long) 1, add.getAddTime(),
                        add.getKhh(),add.getLhh(),add.getName()));
                    return num > 0;
                }
                return true;
            }
            return false;
        }, bankType -> {
            List<SysSydAccount> accs = sysSydAccountMapper.selectSysSydAccountBySydId(id, (short) 0, bankType);
            return accs.size() > 0 ? accs.get(0).getBankCard() : null;
        });
        //平台账户
        Boolean platformRtn = creatXNnum(id,0l,platformProperties.getKhm(),BusRole.PLATFORM.getId(),BusRole.PLATFORM.getId(), add -> {
            if(add != null) {
                return true;
            }
            return false;
        }, bankType -> {
            List<BusAccounts> accs = accountsMapper.selectList(new LambdaQueryWrapper<BusAccounts>()
                .eq(BusAccounts::getSydId,id)
                .eq(BusAccounts::getUnitId,0)
                .eq(BusAccounts::getIsDefault,1)
                .eq(BusAccounts::getBankType,bankType));
            return accs.size() > 0 ? accs.get(0).getBankCard() : null;
        });
        return sydRtn && platformRtn;
    }

    @Override
    public Boolean creatXNnum(Long sydId,Long unitId, String gsmc,int roleType,int addRoleType, Function<BusAccounts,Boolean> saveFun, Function<String,String> existsFun) {
        String failBank = "";
        try {
            try {
                transactionImpl.addZhaoShangAccount(sydId,unitId, gsmc,roleType,addRoleType,saveFun);
            } catch (Exception e) {
                String bankType = "招商银行";
                log.error("结算中心" + bankType + "服务费账户开通出错：" + e.getMessage(), e);
                if (StringUtils.isNotEmpty(failBank)) {
                    failBank += "、";
                }
                failBank += bankType;
            }
            try {
                transactionImpl.addJiaoTongAccount(sydId,unitId, gsmc,roleType,addRoleType,saveFun,existsFun);
            } catch (Exception e) {
                String bankType = "交通银行";
                log.error("结算中心" + bankType + "服务费账户开通出错：" + e.getMessage(), e);
                if (StringUtils.isNotEmpty(failBank)) {
                    failBank += "、";
                }
                failBank += bankType;
            }
            try {
                transactionImpl.addZhiFuBaoAccount(sydId,unitId, gsmc,roleType,addRoleType,saveFun);
            } catch (Exception e) {
                String bankType = "支付宝";
                log.error("结算中心" + bankType + "服务费账户开通出错：" + e.getMessage(), e);
                if (StringUtils.isNotEmpty(failBank)) {
                    failBank += "、";
                }
                failBank += bankType;
            }
            try {
                transactionImpl.addMinShengAccount(sydId,unitId, gsmc,roleType,addRoleType,saveFun);
            } catch (Exception e) {
                String bankType = "民生银行";
                log.error("结算中心" + bankType + "服务费账户开通出错：" + e.getMessage(), e);
                if (StringUtils.isNotEmpty(failBank)) {
                    failBank += "、";
                }
                failBank += bankType;
            }
            if (StringUtils.isNotEmpty(failBank)) {
                throw new ServiceException("开通服务费账户失败[" + failBank + "]");
            }
            return true;
        } catch (Exception e) {
            String msgStr = "开虚拟户失败!";
            log.error(msgStr, e);
            if (e instanceof ServiceException) {
                throw new ServiceException(e.getMessage());
            } else {
                throw new ServiceException(msgStr);
            }
        }
    }

    @Override
    public Map<String, String> valiConfig(Long sydId, String passage) {
        if (StringUtils.isBlank(passage)) {
            throw new ServiceException("bankType不能为空");
        }
        try {
            return bankAccountTransactionImpl.existsBank(sydId, passage);
        } catch (Exception e) {
            String msgStr = "验证银行类型是否可用出错：("+sydId+","+passage+")";
            log.error(msgStr,e);
        }
        return null;
    }

    @Override
    public SysSydSignContent getWorkerSignInfo(int sydId) {
        try {
            SysSydSignContent rtn = signContentDao.selectByPrimaryKey(sydId);
            if (rtn != null) {
                SysSyd syd = baseMapper.selectSysSydById(Long.parseLong(sydId+""));
                rtn.setSignMode(syd.getSignMode());
                rtn.setSignValidTime(syd.getSignValidTime());
            }
            return rtn;
        } catch (Exception e) {
            String msgStr = "查询结算中心的签约内容出错：（"+sydId+"）";
            log.error(msgStr,e);
        }
        return null;
    }

    @Override
    public Boolean saveWorkerSignInfo(SysSydSignContent sign) {
        try {
            sign.setEditTime(new Date());
            transactionImpl.saveWorkerSignInfo(sign);
            return true;
        } catch (Exception e) {
            String msgStr = "保存结算中心的自雇者签约信息出错：（"+ JSONObject.toJSONString(sign)+"）";
            log.error(msgStr,e);
            if(e instanceof ServiceException)
                throw new ServiceException(e.getMessage());
        }
        return false;
    }

    @Override
    public SignZhifubao getSignInfo(Long sydId, String passage) {
        try {
            SysSyd syd = baseMapper.selectSysSydById(Long.parseLong(sydId+""));
            if (syd == null) {
                throw new ServiceException("结算中心已不存在");
            }
            Result<SignZhifubao> signRtn = accountService.getSignInfo(syd.getId(), syd.getGsmc(), passage);
            if (signRtn.hasError()) {
                throw new RuntimeException(signRtn.getResult());
            }else if (signRtn.hasTip()) {
                throw new ServiceException(signRtn.getResult());
            }else if (signRtn.getRtnData() == null) {
                throw new ServiceException("该结算中心无需签约");
            }
            return signRtn.getRtnData();
        } catch (Exception e) {
            String msgStr = "获取结算中心的签约信息出错：（"+sydId+","+passage+"）";
            log.error(msgStr,e);
            if(e instanceof ServiceException)
                throw new ServiceException(e.getMessage());
        }
        return null;
    }

    @Override
    public List<SelectSydVo> selectSydByMerId(Long merId) {
        return baseMapper.selectSydByMerId(merId);
    }



    @Override
    public List<SelectSydVo> getSydByUserName(String userName) {
        List<SelectSydVo> rtn = null;
        RemoteSysUserVo user = remoteUserService.selectUserByName(userName);
        if(user != null && user.getCurRoleId() == BusRole.MERCHANT.getId()){
            rtn = baseMapper.selectSydByMerId(user.getBusId());
        }
        return rtn;
    }
}
