package com.tuoheng.admin.service.inspection.update.flyer;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tuoheng.admin.dto.StreamingDto;
import com.tuoheng.admin.entity.Business;
import com.tuoheng.admin.entity.Inspection;
import com.tuoheng.admin.entity.InspectionFile;
import com.tuoheng.admin.entity.LiveChannel;
import com.tuoheng.admin.enums.ChannelStatusEnum;
import com.tuoheng.admin.mapper.BusinessMapper;
import com.tuoheng.admin.mapper.InspectionFileMapper;
import com.tuoheng.admin.mapper.InspectionMapper;
import com.tuoheng.admin.mapper.LiveChannelMapper;
import com.tuoheng.admin.request.inspection.UpdateTaskByCodeRequest;
import com.tuoheng.admin.vo.DspCallbackVo;
import com.tuoheng.common.core.constant.CommonConstants;
import com.tuoheng.common.core.enums.HttpStatusEnum;
import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.DateUtils;
import com.tuoheng.common.core.utils.JacksonUtil;
import com.tuoheng.common.core.utils.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;

@Slf4j
@Service
public class OnlineIdentifService {

    @Autowired
    private InspectionMapper inspectionMapper;

    @Autowired
    private InspectionFileMapper inspectionFileMapper;

    @Autowired
    private LiveChannelMapper liveChannelMapper;

    @Autowired
    private BusinessMapper businessMapper;

    @Autowired
    private GetLiveStatusService getLiveStatusService;

    @Autowired
    private DeliverStreamingService deliverStreamingService;

    @Autowired
    @Qualifier("restTemplate")
    private RestTemplate restTemplate;

    @Value("${tuoheng.live-channel-domain-url:}")
    private String channel_url;

    /**
     * DSP服务API接口域名
     */
    @Value("${tuoheng.dsp-domain-url:}")
    private String dspDomainUrl;

    @Value("${tuoheng.dsp-service-inst-id:}")
    private String dspServiceInstId;

    @Value("${tuoheng.dsp-callback-url:}")
    private String dspCallbackUrl;

    public void handle(UpdateTaskByCodeRequest request, Inspection inspection) {
        log.info("=========================在线识别开始=========================");
        if (request.getChannelCode() == null) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "请选择通道");
        }
        StreamingDto dto = getLiveStatusService.getLiveStatus(request.getChannelCode());

        this.useLiveChannel(new StreamingDto(request.getChannelCode()));

        log.info("更新巡检任务状态");
        Inspection updateAnalyseStatus = new Inspection();
        //原本是请求id->(任务id)
        updateAnalyseStatus.setId(inspection.getId());
        updateAnalyseStatus.setAnalyseStatus(2);
        updateAnalyseStatus.setAiVideoUrl("");
        updateAnalyseStatus.setHeartbeatTime(System.currentTimeMillis());
        inspectionMapper.updateById(updateAnalyseStatus);

        //查询问题数
        Integer num = inspectionFileMapper.selectCount(new LambdaQueryWrapper<InspectionFile>()
                .eq(InspectionFile::getTenantId, inspection.getTenantId())
                .eq(InspectionFile::getInspectionId, inspection.getId())
                .eq(InspectionFile::getMark, 1));
        if (num > 0) {
            // 清空旧数据
            inspectionFileMapper.deleteByInspectionId(inspection.getId());
        }

        log.info("开始调用DSP服务");

        // 调用DSP服务
        String url = String.format(Locale.ENGLISH, "%s/api/web/serviceInst/%s/application", dspDomainUrl, dspServiceInstId);
        log.info("调用DSP服务, url:{}", url);
        try {
            Map<String, Object> paramMap = new HashMap<>();

            List<Map<String, Object>> configMapList = new ArrayList<>();
            // 运行模式
            Map<String, Object> serviceModeMap = new HashMap<>();
            serviceModeMap.put("ename", "service_mode");
            serviceModeMap.put("evalue", 1);
            configMapList.add(serviceModeMap);
            // 回调地址
            Map<String, Object> callbackUrlMap = new HashMap<>();
            callbackUrlMap.put("ename", "callback_url");
            callbackUrlMap.put("evalue", dspCallbackUrl);
            configMapList.add(callbackUrlMap);
            paramMap.put("serviceInstConfigList", configMapList);

            // 请求入参
            List<Map<String, Object>> reqMapList = new ArrayList<>();

            Map<String, Object> pushUrlMap = new HashMap<>();
            pushUrlMap.put("ename", "push_url");
            pushUrlMap.put("evalue", dto.getPushUrl());
            reqMapList.add(pushUrlMap);

            Map<String, Object> map3 = new HashMap<>();
            map3.put("ename", "pull_url");
            map3.put("evalue", dto.getPullUrl());
            reqMapList.add(map3);
            paramMap.put("serviceInstReqList", reqMapList);

            log.info(String.format("DSP入参：%s", paramMap));
            log.info("发起DSP服务调用网络请求");
            HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(paramMap);
            ResponseEntity<JsonResult<DspCallbackVo>> response = restTemplate.exchange(url, HttpMethod.POST, httpEntity, new ParameterizedTypeReference<JsonResult<DspCallbackVo>>() {
            });
            log.info(String.format("请求结果：%s", response.getBody()));
            if (response == null || !response.hasBody()) {
                log.error("调用DSP只能分析服务失败,响应体为空!");
                throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "调用DSP只能分析服务失败，请重试");
            }
            JsonResult<DspCallbackVo> jsonResult = response.getBody();
            log.info(String.format("结果对象转换：%s", jsonResult.getData()));
            if (jsonResult.getCode() == HttpStatusEnum.NO_RESOURCES.getCode()) {
                log.warn("调用DSP只能分析服务失败, response:{}", JacksonUtil.obj2json(jsonResult));
                throw new ServiceException(HttpStatus.BAD_REQUEST.value(), HttpStatusEnum.NO_RESOURCES.getDescription());
            }
            log.info("创建或更新通道记录");
            // 创建通道记录数据
            DspCallbackVo dspCallbackVo = jsonResult.getData();
            log.info("dsp响应体：{}", JacksonUtil.obj2StringPretty(dspCallbackVo));

            // 通道表新增
            LiveChannel liveChannel = new LiveChannel();
            liveChannel.setInspectionId(inspection.getId());
            liveChannel.setDeptId(inspection.getDeptId());
            liveChannel.setChannelCode(request.getChannelCode());
            // 修改通道名
            liveChannel.setName(dto.getName());
            liveChannel.setTenantId(inspection.getTenantId());
            liveChannel.setPushUrl(dspCallbackVo.getPushUrl());
            liveChannel.setPullUrl(dspCallbackVo.getPlayUrl());
            liveChannel.setAipushUrl(dspCallbackVo.getAipushUrl());
            liveChannel.setAipullUrl(dspCallbackVo.getAiplayUrl());
            liveChannel.setCreateTime(DateUtils.now());
            liveChannel.setUpdateTime(DateUtils.now());

            // 查验是否存在
            LiveChannel liveChannelTmp = liveChannelMapper.selectOne(new LambdaQueryWrapper<LiveChannel>()
                    .eq(LiveChannel::getInspectionId, inspection.getId())
                    .eq(LiveChannel::getMark, 1));
            if (liveChannelTmp == null) {
                // 添加通道使用记录
                liveChannelMapper.insert(liveChannel);
            } else {
                // 更新通道使用记录
                liveChannel.setId(liveChannelTmp.getId());
                liveChannelMapper.updateById(liveChannel);
            }

            log.info("创建业务表数据");
            // 添加业务表数据
            insertBusiness(dspCallbackVo.getRequestId(), inspection.getId(), inspection.getTenantId());
        } catch (Exception e) {
            log.error("DSP服务调用失败", e);
            // 释放小程序选择的通道
            deliverStreamingService.deliver(request.getChannelCode());
            throw e;

        }
        log.info("=========================在线识别调用结束=========================");
    }

    private JsonResult<Void> useLiveChannel(StreamingDto liveChannelDto) {
        StreamingDto channelDto = getLiveStatusService.getLiveStatus(liveChannelDto.getCode());
        // 通道只有空闲状态才能设置占用中
        if (ChannelStatusEnum.IDLE.getCode() != channelDto.getStatus()) {
            log.error("通道状态不是空闲中，不能设置通道状态为占用状态!");
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "通道不是空闲状态，请稍后再试！");
        }
        String url = String.format(Locale.ENGLISH, "%s%s", channel_url, LiveChannelConstant.LIVE_CHANNEL_USELIVECHANNEL_URL);
        HttpEntity httpEntity = new HttpEntity(liveChannelDto);
        ResponseEntity<JsonResult> response;
        try {
            response = restTemplate.exchange(url, HttpMethod.PUT, httpEntity, JsonResult.class);
        } catch (Exception e) {
            deliverStreamingService.deliver(liveChannelDto.getCode());
            log.error("设置通道状态异常！{}", e);
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "设置通道状态异常！");
        }
        if (response == null || !response.hasBody() || response.getBody().getCode() != JsonResult.SUCCESS) {
            deliverStreamingService.deliver(liveChannelDto.getCode());
            log.error("设置占用通道状态失败!");
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "设置通道状态异常！");
        }
        return response.getBody();
    }

    /**
     * 保存kafka信息id和任务id,用于后期取出消息处理任务逻辑
     *
     * @param msgId kafka消息id
     * @param id    任务id
     */
    private void insertBusiness(String msgId, String id, String tenantId) {
        // 将消息任务和kafka任务id消息存入数据库，用于监听获取任务信息
        Business business = new Business();
        business.setMsgId(msgId);
        business.setTenantId(tenantId);
        business.setType(CommonConstants.INSPECTION_TASK_TYPE);
        business.setTypeId(id);
        business.setCreateTime(DateUtils.now());
        business.setUpdateTime(DateUtils.now());
        business.setMark(1);
        // 查询任务是否存在
        int result = businessMapper.selectCount(new LambdaQueryWrapper<Business>()
                .eq(Business::getMsgId, msgId)
                .eq(Business::getMark, 1));
        if (result > 0) { // 做了一层保护，可有可无
            businessMapper.update(business, new LambdaQueryWrapper<Business>()
                    .eq(Business::getMsgId, msgId)
                    .eq(Business::getMark, 1));
        } else {
            businessMapper.insert(business);
        }
    }

}
