package com.chushang.inspection.work.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chushang.common.core.constant.SecurityConstants;
import com.chushang.common.core.exception.utils.AssertUtil;
import com.chushang.common.core.web.Result;
import com.chushang.common.mybatis.page.CommonParam;
import com.chushang.common.mybatis.utils.PageResult;
import com.chushang.common.mybatis.utils.WrapperUtils;
import com.chushang.datascope.annotation.DataScope;
import com.chushang.inspection.project.po.PollingTask;
import com.chushang.inspection.project.po.WrkProjectPayment;
import com.chushang.inspection.project.service.PollingTaskService;
import com.chushang.inspection.terminal.po.Store;
import com.chushang.inspection.terminal.po.Terminal;
import com.chushang.inspection.terminal.po.TerminalIns;
import com.chushang.inspection.terminal.service.StoreService;
import com.chushang.inspection.terminal.service.TerminalService;
import com.chushang.inspection.utils.BeanCopyUtils;
import com.chushang.inspection.utils.PoolUtils;
import com.chushang.inspection.utils.TaskConfigUtils;
import com.chushang.inspection.work.dto.BankDispatchQuery;
import com.chushang.inspection.work.dto.DispatchDTO;
import com.chushang.inspection.work.dto.WrkIcbcJsPush;
import com.chushang.inspection.work.dto.WrkIcbcJsReceive;
import com.chushang.inspection.work.enums.BankBranchesEnum;
import com.chushang.inspection.work.enums.WorkTypeOperation;
import com.chushang.inspection.work.po.WrkInfo;
import com.chushang.inspection.work.service.WrkInfoDispatchService;
import com.chushang.inspection.work.service.WrkIcbcJsService;
import com.chushang.inspection.work.service.WrkInfoService;
import com.chushang.inspection.work.vo.BankDispatchDTO;
import com.chushang.inspection.work.vo.WrkInfoDetailsVO;
import com.chushang.inspection.work.vo.WrkInfoVO;
import com.chushang.security.entity.po.SysUser;
import com.chushang.system.feign.RemoteUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chushang.inspection.work.mapper.WrkIcbcJsMapper;
import com.chushang.inspection.work.po.WrkIcbcJs;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
  * @auther: zhao
  * @date: 2024/6/28 15:38
  */
@Slf4j
@Service
public class WrkIcbcJsServiceImpl extends ServiceImpl<WrkIcbcJsMapper, WrkIcbcJs> implements WrkIcbcJsService {

    @Resource
    StoreService storeService;
    @Resource
    TerminalService terminalService;
    @Resource
    PollingTaskService taskService;
    @Resource
    RemoteUserService remoteUserService;
    @Resource
    WrkInfoService wrkInfoService;
    @Resource
    WrkInfoDispatchService dispatchService;
    private static final String SIGN = "sign";

    @Value("${push.icbc-js.url:''}")
    private String url;

    @Value("${push.icbc-js.sign:''}")
    private String sign;


    @Override
    @Transactional
    public void receive(WrkIcbcJsReceive dto) {
        Store store = storeService.save(dto);
        JSONObject terJson = terminalService.save(store, dto);
        WrkIcbcJs wrkIcbcJs = save(dto, terJson, store);
        // 派单
        PoolUtils.SENTINEL.getInstance().execute(()-> dispatchOrder(wrkIcbcJs, terJson, store, null));
    }

    private WrkIcbcJs save(WrkIcbcJsReceive dto, JSONObject terJson, Store store) {
        Terminal terminal = terJson.getObject("terminal", Terminal.class);
        // 江苏工行实体类信息
        WrkIcbcJs wrkIcbcJs = BeanUtil.copyProperties(dto, WrkIcbcJs.class);
        wrkIcbcJs.setStatus(1);
        wrkIcbcJs.setStoreId(store.getStoreId());
        wrkIcbcJs.setTerminalId(terminal.getTerminalId());
        wrkIcbcJs.setIsBank((byte) '1');
        save(wrkIcbcJs);
        return wrkIcbcJs;
    }

    @Override
    @DataScope
    public PageResult queryDispatchPage(BankDispatchQuery query) {
        CommonParam commonParam = CommonParam.buildPageRequest();
        LambdaQueryWrapper<WrkIcbcJs> sql = WrapperUtils.builder(query, commonParam);
        IPage<WrkIcbcJs> page = this.page(
                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(commonParam.getPage(), commonParam.getLimit()),
                sql
        );
        return new PageResult(page);
    }

    @Override
    public BankDispatchDTO info(Long id) {
        return BeanUtil.copyProperties(getById(id), BankDispatchDTO.class);
    }

    @Override
    public void update(BankDispatchDTO dispatch) {
        WrkIcbcJs entity = BeanUtil.copyProperties(dispatch, WrkIcbcJs.class);
        entity.setStatus(null);
        entity.setReqDate(null);
        updateById(entity);
    }

    @Override
    public void dispatchOrder(WrkIcbcJs entity, Long userId) {
        Long id = entity.getId();
        WrkIcbcJs wrkIcbcJs = getById(id);
        AssertUtil.invalidate(ObjectUtil.isEmpty(wrkIcbcJs), "未找寻到对应银行工单");
        Store store = storeService.getById(wrkIcbcJs.getStoreId());
        AssertUtil.invalidate(ObjectUtil.isEmpty(store), "未找寻到对应商户信息");
        JSONObject terJson = terminalService.getTerMap(wrkIcbcJs.getTerminalId());
        dispatchOrder(entity, terJson, store, userId);
    }

    /**
     * TODO 需要创建对应的任务以及 业务员信息
     * @param entity
     * @param terJson
     * @param store
     * @param userId
     */
    public void dispatchOrder(WrkIcbcJs entity, JSONObject terJson, Store store, Long userId)
    {
        Terminal terminal = terJson.getObject("terminal", Terminal.class);
        TerminalIns terminalIns = terJson.getObject("terminalIns", TerminalIns.class);
        WrkIcbcJs icbcJs = entity.getArea() != null ? entity : getById(entity.getId());

        AssertUtil.invalidate(icbcJs.getStatus() != 1, "只有下发状态才能派单");
        DispatchDTO dispatch = new DispatchDTO().dispatch(icbcJs);
        WrkInfo wrkInfo;
        if (null == userId){
            Long lowerTaskId = BankBranchesEnum.getByCode(icbcJs.getArea());
            AssertUtil.invalidate(lowerTaskId == null, "没有找到对应的分行");
            PollingTask task = taskService.getById(lowerTaskId);
            AssertUtil.invalidate(task == null && StrUtil.isEmpty(task.getContact()), "未指定业务员");
            Result<Map<String, Long>> result = remoteUserService.getIdByNicknames(Set.of(), SecurityConstants.INNER);
            AssertUtil.invalidate(!result.isSuccess(), "获取业务员信息失败");
            userId = result.getData().get(task.getContact());
            wrkInfo = dispatchWrkInfo(dispatch, userId, task.getContact(), WorkTypeOperation.valueOfCode(icbcJs.getOrderType()));
        } else {
            Result<SysUser> result = remoteUserService.getInfoById(userId, SecurityConstants.INNER);
            AssertUtil.invalidate(!result.isSuccess(), "获取业务员信息失败");
            wrkInfo = dispatchWrkInfo(dispatch, userId, result.getData().getNickName(), WorkTypeOperation.valueOfCode(icbcJs.getOrderType()));
        }
        // 派单
        Long wrkId = wrkInfoService.dispatch(wrkInfo, store, terminal, terminalIns);
        if (!TaskConfigUtils.isRepeat(dispatch.getTaskId())) {
            // 修改 终端占用
            terminalService.updateOccupy(ListUtil.toList(terminal.getTerminalId()), 1);
        }
        // 修改派单进度
        dispatchService.updateWorkOrderProgress(userId,6, ListUtil.toList(wrkId), wrkInfo.getDeptId());
        WrkIcbcJs wrkIcbcJs = new WrkIcbcJs();
        wrkIcbcJs.setId(entity.getId());
        wrkIcbcJs.setWrkId(wrkId);
        wrkIcbcJs.setStatus(2);
        // 修改 银行派单状态
        updateById(wrkIcbcJs);
    }

    private WrkInfo dispatchWrkInfo(DispatchDTO dispatch, Long userId, String userName, Integer workType) {
        WrkInfo wrkInfo = BeanUtil.copyProperties(dispatch, WrkInfo.class);
        wrkInfo.setUserId(userId);
        wrkInfo.setWorkNo(IdUtil.getSnowflake().nextId());
        wrkInfo.setUserName(userName);
        wrkInfo.setWrkStatus(1);
        wrkInfo.setWorkType(workType);
        wrkInfo.setWorkSource(3);
        return wrkInfo;
    }

    @Override
    public void manualPush(Long id) {
        WrkIcbcJs entity = getById(id);
        Assert.notNull(entity, "选择的数据不存在");
        Assert.isTrue(entity.getStatus().equals(4), "只有自动推送失败时才能手动推送");
        com.chushang.inspection.work.vo.Result result = sendHttp(BeanCopyUtils.copy(entity, WrkIcbcJsPush.class));
        if (result != null && result.getRespCode().equals("00")) {
            entity.setStatus(3);
            updateById(entity);
        } else {
            entity.setStatus(4);
            updateById(entity);
            Assert.isTrue(false, result != null ? result.getRespMssg() : "推送江苏工行数据失败");
        }
    }

    @Override
    public void push(WrkInfoDetailsVO infoDetail) {
        WrkInfoVO wrkInfo = infoDetail.getWrkInfo();
        WrkIcbcJs entity = getOne(new LambdaQueryWrapper<WrkIcbcJs>()
                .eq(WrkIcbcJs::getWrkId, wrkInfo.getWrkId())
                .last(" LIMIT 1")
        );
        if (entity == null) {
            String area = BankBranchesEnum.getByLowerTaskId(wrkInfo.getLowerTaskId());
            if (area == null && wrkInfo.getLowerTaskId() != 0) {
                PollingTask task = taskService.getById(wrkInfo.getLowerTaskId());
                if (task != null) {
                    List<String> split = StrUtil.split(task.getSearchNum(), "-");
                    if (split.size() > 2) {
                        PollingTask pollingTask = taskService.getOne(new LambdaQueryWrapper<PollingTask>()
                                        .select(PollingTask::getId)
                                .eq(PollingTask::getSearchNum, split.get(0) + "-" + split.get(1) + "-"));
                        area = BankBranchesEnum.getByLowerTaskId(pollingTask.getId());
                    }
                }
            }
            entity = new WrkIcbcJs().save(infoDetail, area);
            save(entity);
        } else {
            entity = entity.push(infoDetail);
        }
        com.chushang.inspection.work.vo.Result result = sendHttp(BeanCopyUtils.copy(entity, WrkIcbcJsPush.class));
        if (result != null && result.getRespCode().equals("00")) {
            entity.setStatus(3);
            updateById(entity);
        } else {
            entity.setStatus(4);
            String msg = result != null ? result.getRespMssg() : "推送江苏工行数据失败";
            entity.setRespMssg(msg);
            updateById(entity);
        }
    }

    private com.chushang.inspection.work.vo.Result sendHttp(WrkIcbcJsPush wrkIcbcJsPush) {
        HttpRequest request = HttpRequest.post(url);
        String parse = JSONObject.toJSONString(wrkIcbcJsPush);
        request.header(SIGN, SecureUtil.md5(parse + sign));
        request.body(parse, "application/json");
        request.timeout(3000);
        log.info("推送数据 ：url【{}】header【{}】body【{}】", url, request.headers(), parse);
        try (HttpResponse response = request.execute()) {
            com.chushang.inspection.work.vo.Result result = JSONObject.parseObject(response.body(),
                    com.chushang.inspection.work.vo.Result.class);
            log.info("江苏工行工单推送：【{}】，返回数据【{}】", parse, result);
            return result;
        } catch (Exception e) {
            log.error("解析回送数据失败", e);
            return null;
        }
    }
}
