package com.mvc.recognition.freeai;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mvc.constant.DeviceType;
import com.mvc.constant.ReviewResultType;
import com.mvc.entity.TaskReview;
import com.mvc.model.*;
import com.mvc.model.aiiden.AiIdenMap;
import com.mvc.netty.dealconstant.HandleMsgCode;
import com.mvc.netty.dealconstant.ResourcePath;
import com.mvc.netty.dealconstant.ResourceTag;
import com.mvc.service.aiiden.TaskReviewService;
import com.mvc.service.copy.TAireadService;
import com.mvc.service.copy.TExtendIdentService;
import com.mvc.service.copy.TServerReadService;
import com.mvc.service.taizhang.DeviceAccService;
import com.mvc.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Base64;

/**
 * 免配置识别(与MCU机制相同的版本)
 */
@Component
public class FreeAiRecognition {

    private static Logger log = LoggerFactory.getLogger(FreeAiRecognition.class);

    @Resource
    private Environment env;

    @Resource
    private TExtendIdentService extendIdentService;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private TaskReviewService taskReviewService;

    @Resource
    private TAireadService aireadService;

    @Resource
    private TServerReadService serverReadService;

    @Resource
    private DeviceAccService deviceAccService;

    /**
     * 免配置识别
     *
     * @param aireadModel
     * @param cfgModel
     */
    public TServerReadModel handleFreeAi(TAireadModel aireadModel, TAicbqCfgModel cfgModel) {
        TServerReadModel serverReadModel = null;
        if (StringUtils.isEmpty(aireadModel.getBigJpgUrl())) {
            return null;
        }
        String url = env.getProperty(ResourceTag.NoConfigServerUrlTag.getTag());

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        String imgPath = ImageUtil.convertImageUrlToLocalPath(aireadModel.getBigJpgUrl(), env.getProperty(ResourceTag.UploadPathTag.getTag()));

        File file = new File(imgPath);
        if (!file.exists() || file.isDirectory()) {
            AiIdenMap aiIdenMap = new AiIdenMap();
            aiIdenMap.setCode("IMGERR");
            return null;
        } else if (file.length() == 0) {
            log.info("FreeAi-图片大小为0,SN:{},Image:{}", aireadModel.getDeviceSn(), imgPath);
            return null;
        }
        FileSystemResource resource = new FileSystemResource(file);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();

        FaSampleInfo sampleInfo = new FaSampleInfo(aireadModel);
        sampleInfo.setImgDataSize((int) file.length());
        TaskReview taskReview = getTaskReviewModel(aireadModel);
        if (taskReview != null) {
            sampleInfo.setReviewValue(taskReview.getReviewValue());
            sampleInfo.setReviewSampleTime(taskReview.getSampleTime());
            log.info("FreeAi-使用审核值,SN:{},value:{}", aireadModel.getDeviceSn(), taskReview.getReviewValue());
        }

        String cfgJson = "";
        if (cfgModel != null) {
            //如果是燃气表,启用人工配置(不然0.01不生效) 2025-01-18 guozhao
            DeviceAccModel accModel = deviceAccService.findDeviceAccBysn(aireadModel.getDeviceSn());
            if (accModel != null && DeviceType.GAS_METER.getCode().equals(cfgModel.getDeviceType())) {
                cfgModel.setEnableNoconfigManualConfig("1");
            }
            cfgJson = JSON.toJSONString(cfgModel);
        }

        map.add("file", resource);
        map.add("configModelJson", cfgJson);
        map.add("sampleInfoJson", JSON.toJSONString(sampleInfo));

        try {
            HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(map, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);

            if (response.getStatusCode() == HttpStatus.OK) {
                String body = response.getBody();
                log.info("FreeAI-识别结果:" + response.getBody());

                /*使用常用的转换方式部署在服务器会报错(本地正常) 2024-08-27 guozhao
                cannot be cast to class com.mvc.recognition.freeai.FaSampleResult (com.alibaba.fastjson.JSONObject and com.mvc.recognition.freeai.
                FaSampleResult are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader*/

                JSONObject jsonObject = JSON.parseObject(body);
                Integer code = jsonObject.getInteger("code");
                String msg = jsonObject.getString("msg");

                if (code == HttpStatus.OK.value()) {
                    serverReadModel = getServerReadModel(aireadModel, imgPath, jsonObject);
                    serverReadService.saveTServerRead(serverReadModel);

                    if (aireadModel.getFunCode().equals(HandleMsgCode.H_32.getCode())) {//如果没有MCU的识别值,则更新ResultValue为服务侧值
                        if (aireadModel.getIdentValue() == null && aireadModel.getRawValue() == null) {
                            aireadModel.setResultValue(serverReadModel.getIdentValue());
                        }
                        aireadService.updateTAiread(aireadModel);
                    }
                } else {
                    log.error("FreeAI识别失败", msg);
                }
            } else {
                log.error("FreeAI接口调用失败", response.getStatusCodeValue());
            }
        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
        return serverReadModel;
    }

    /**
     * 获取服务侧识别结果对象
     *
     * @param aireadModel
     * @param imgPath
     * @param jsonObject
     * @return
     */
    private TServerReadModel getServerReadModel(TAireadModel aireadModel, String imgPath, JSONObject jsonObject) {
        TServerReadModel serverReadModel = null;
        JSONObject resObject = jsonObject.getJSONObject("data");
        if (resObject != null) {
            FaSampleResult faSampleResult = JSON.parseObject(resObject.toJSONString(), FaSampleResult.class);

            serverReadModel = new TServerReadModel();
            serverReadModel.setDeviceSn(aireadModel.getDeviceSn());
            serverReadModel.setAireadId(aireadModel.getAireadId());
            serverReadModel.setStationCode(aireadModel.getStationCode());

            if (StringUtils.isNotEmpty(faSampleResult.getRecogResult())) {
                serverReadModel.setIdentValue(new BigDecimal(faSampleResult.getRecogResult()));
            }
            serverReadModel.setJpgUrl(faSampleResult.getRunLogUrl());
            if (faSampleResult.getAiResult_array() != null) {
                String debugInfo = StringUtil.debugInfoToString(faSampleResult.getAiResult_array());
                String[] debugInfoArray = debugInfo.split(";");
                serverReadModel.setSzsbz(debugInfoArray[0]);
                serverReadModel.setSzsbgl(debugInfoArray[1]);
                serverReadModel.setGoodFlag(faSampleResult.getAiResult_array()[0][11].toString());
                serverReadModel.setResultCode(serverReadModel.getGoodFlag());
            }
            if (StringUtils.isNotEmpty(faSampleResult.getSls_imgDataBase64())) {
                serverReadModel.setSmallJpgType(faSampleResult.getSls_imgHeaderIndex().toString());
                serverReadModel.setSmallJpgHeight(faSampleResult.getSls_imgHeight());
                serverReadModel.setSmallJpgWidth(faSampleResult.getSls_imgWidth());
                String smallJpgUrl = saveSmallJpg(aireadModel, faSampleResult);
                //小图要保存
                serverReadModel.setSmallJpgUrl(smallJpgUrl);
            }

            //TExtendIdentModel model = new TExtendIdentModel(faSampleResult, aireadModel);
            //先根据aireadId和识别类型删除一次(现在有中图和大图的情况,会生成两条记录) 2024-09-07 guozhao
            //extendIdentService.deleteTExtendIdentByAireadIdAndIdentType(model.getAireadId(), model.getIdentType());
            //extendIdentService.saveTExtendIdent(model);
        } else {
            log.info("FreeAi-请求成功,但识别结果为空,SN:{},Image:{}", aireadModel.getDeviceSn(), imgPath);
        }
        return serverReadModel;
    }

    //保存小图
    private String saveSmallJpg(TAireadModel tAireadModel, FaSampleResult sampleResult) {
        String date = DateUtil.formateDate(tAireadModel.getSampleTime(), "yyyy-MM");
        String path0 = String.format("%s%s", env.getProperty(ResourceTag.UploadPathTag.getTag()), ResourcePath.Rawdata.getPath());
        String path1 = String.format("%s/%s/", date, tAireadModel.getStationCode());//业务路径,要存进数据库

        String sampleTime = DateUtil.formateDate(tAireadModel.getSampleTime(), "yyyyMMddHHmmss");
        String fileName = String.format("%s_small_%d_%d_%d.jpg", sampleTime, sampleResult.getSls_imgHeaderIndex(), sampleResult.getSls_imgHeight(), sampleResult.getSls_imgWidth());

        try {
            //没有图片头的
            byte[] imgDataBase64 = Base64.getDecoder().decode(sampleResult.getSls_imgDataBase64());
            //图片头编号
            String picbianhao = StringUtils.leftPad(sampleResult.getSls_imgHeaderIndex().toString(), 2, '0');
            byte[] result = ImageUtil.prependImageHeader(imgDataBase64, picbianhao, sampleResult.getSls_imgWidth(), sampleResult.getSls_imgHeight());

            FileUtil.writeBytesFile(path0 + path1, fileName, result);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "/" + path1 + fileName;
    }

    /**
     * 获取任务审核记录
     *
     * @param aireadModel
     * @return
     */
    private TaskReview getTaskReviewModel(TAireadModel aireadModel) {
        TExtendIdentModel lastIdent = extendIdentService.findLatestTExtendIdent(aireadModel.getStationCode(), 5);
        if (lastIdent == null) {
            return null;
        }

        TAireadModel lastAireadModel = aireadService.getTaireadById(lastIdent.getAireadId());
        if (lastAireadModel == null) {
            return null;
        }

        TaskReview review = taskReviewService.findTaskReviewByAireadId(lastAireadModel.getAireadId());
        if (review == null || review.getReviewValue() == null) {//审核记录无效
            return null;
        }

        //审核状态不是正确或修正
        if (!review.getFinishedFlag().equals(ReviewResultType.IDENT_TRUE.getCode()) && !review.getFinishedFlag().equals(ReviewResultType.REVIEW_REVISE.getCode())) {
            return null;
        }

        //当免服识别无效或审核结果与免服识别结果不一致时，才返回审核记录
        if (lastIdent.getIdentValue() == null || review.getReviewValue().compareTo(lastIdent.getIdentValue()) != 0) {
            return review;
        }

        return null;
    }
}
