package com.mvc.service.aiiden;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.mvc.model.StationAccModel;
import com.mvc.model.TAicbqCfgModel;
import com.mvc.model.TAireadModel;
import com.mvc.model.aiiden.AiIdenMap;
import com.mvc.model.aiiden.AiMeterParmModel;
import com.mvc.model.aiiden.AiMeterResultModel;
import com.mvc.model.aiiden.AiTokenModel;
import com.mvc.netty.dealconstant.ResourcePath;
import com.mvc.netty.dealconstant.ResourceTag;
import com.mvc.service.taizhang.StationAccService;
import com.mvc.service.taizhang.TAicbqCfgService;
import com.mvc.utils.DateUtil;
import com.mvc.utils.FileUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;

@Service
public class AiIdenService {
    private static Logger log = LoggerFactory.getLogger(AiIdenService.class);
    private static AiTokenModel aiTokenModel;                                               //存储当前有效的Token
    private static String api_getToken="/api/v1/auth/login?name=admin&password=admin";      //获取token的接口
    private static String api_getResult="/api/v1/ai/water_meter";                           //获取识别结果接口
    private static String api_getImage="/api/v1/ai/water_meter/ai_image";                   //获取识别标注图接口
    private static int api_token_validity=1800;                                             //token有效期30分钟

    @Autowired
    private RestTemplate restTemplate;

    @Resource
    private Environment env;

    @Autowired
    private TAicbqCfgService tAicbqCfgService;

    @Autowired
    private StationAccService stationAccService;

    /**
     * 获取Token(超30分钟自动刷新)
     * @return
     */
    private AiTokenModel getTocken(){
        if(aiTokenModel!=null){
            Date now=new Date();
            long span=now.getTime()-aiTokenModel.getAccess_time().getTime();
            if(span/1000<api_token_validity){
                return aiTokenModel;
            }
        }

        String url=env.getProperty(ResourceTag.AiIdenserverUrlTag.getTag())+ api_getToken;
        ResponseEntity<String> entity = restTemplate.postForEntity(url,"",String.class);
        if(entity.getStatusCode()==HttpStatus.OK){
            String body=entity.getBody();
            AiIdenMap map= JSON.parseObject(body, new TypeReference<AiIdenMap<AiTokenModel>>(){});
            if(map.getCode().equals("5200")){
                aiTokenModel=(AiTokenModel)map.getResult();
                aiTokenModel.setAccess_time(new Date());
            }
            else {
                System.out.println(map.getResult());
            }
        }
        else {
            System.out.println(entity.getStatusCode());
        }

        return aiTokenModel;
    }

    /**
     * 获取水表识别结果
     * @param model
     * @return
     */
    public AiIdenMap getWaterResult(AiMeterParmModel model){
        String url=env.getProperty(ResourceTag.AiIdenserverUrlTag.getTag())+api_getResult;
        HttpHeaders headers=new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.add("Authorization","Bearer "+getTocken().getAccess_token());
        String imgPath=getImageLocalPath(model.getImage_file());
        File file=new File(imgPath);
        if(!file.exists()||file.isDirectory()){
            AiIdenMap aiIdenMap=new AiIdenMap();
            aiIdenMap.setCode("IMGERR");
            return aiIdenMap;                //图片不存在
        }
        FileSystemResource resource=new FileSystemResource(file);
        MultiValueMap<String,Object> map=new LinkedMultiValueMap<String,Object>();
        map.add("image_file",resource);
        StringBuilder sb=new StringBuilder();
        sb.append("-----服务侧识别参数:");
        try{
            //反射添加参数
            Field[] fields =  model.getClass().getDeclaredFields();
            for( int i = 0; i < fields.length; i++){
                Field f = fields[i];
                f.setAccessible(true);
                Object value=f.get(model);
                if(value!=null&& !map.containsKey(f.getName())){
                    map.add(f.getName(),f.get(model));
                    sb.append(f.getName()+"="+f.get(model)+";");
                }
            }
            log.info(sb.toString());
            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("服务侧识别结果:"+body);
                AiIdenMap aiIdenMap= JSON.parseObject(body, new TypeReference<AiIdenMap<AiMeterResultModel>>(){});
/*                if(aiIdenMap.getCode().equals("5200")){
                    AiMeterResultModel resultModel=(AiMeterResultModel)aiIdenMap.getResult();
                    log.info("服务器侧识别结果:"+resultModel.getValue()+",img:"+resultModel.getAi_image_url());
                    return resultModel;
                }
                else {
                    System.out.println(aiIdenMap.getResult());
                }*/
                return aiIdenMap;
            }
            else {
                String body=response.getBody();
                AiIdenMap aiIdenMap= JSON.parseObject(body, new TypeReference<AiIdenMap<String>>(){});
                String info="StatusCode:"+response.getStatusCode();
                if(aiIdenMap!=null){
                    info+=";Code:"+aiIdenMap.getCode()+";Result:"+aiIdenMap.getResult();
                }
                System.out.println(info);
                return aiIdenMap;
            }
        }
        catch (RestClientException re){
            re.printStackTrace();
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取IA识别后标注的图片
     * @param imageName
     * @param isSaveDiff 是否保存到diff目录(代表MCU和服务侧识别不一样的)
     */
    public String getAiResultImage(String imageName,boolean isSaveDiff) throws IOException {
        //保存路径是UploadPathTag下的server目录
        String param="?ai_image_url="+imageName+"&access_token="+getTocken().getAccess_token();
        String url=env.getProperty(ResourceTag.AiIdenserverUrlTag.getTag())+api_getImage+param;
        ResponseEntity<byte[]> entity = restTemplate.getForEntity(url,byte[].class);
        if(entity.getStatusCode()==HttpStatus.OK){
            byte[] buffer=entity.getBody();

            Date now =new Date();
            String dirDate = DateUtil.getCurrentTime("yyyy-MM");
            //拼接上月份,直接放到一个目录中,文件夹内容太琐碎 2023-01-02 guozhao
            String path=env.getProperty(ResourceTag.UploadPathTag.getTag())+"/server/"+dirDate+"/";

            File serFolder = new File(path);
            if(!serFolder.exists()){
                serFolder.mkdirs();
            }

            FileUtil.writeBytesFile(path, imageName, buffer);

            if(isSaveDiff){
                String diff=env.getProperty(ResourceTag.UploadPathTag.getTag())+"/diff/";
                File folder = new File(diff);
                if(!folder.exists()){
                    folder.mkdirs();
                }
                FileUtil.writeBytesFile(diff, imageName, buffer);
            }

            String imageUrl=env.getProperty(ResourceTag.ResourceUrlTag.getTag())+"/image/server/"+dirDate+"/"+imageName;
            log.info("返回识别后的图片路径:"+imageUrl);
            return imageUrl;
        }
        else {
            System.out.println(entity.getStatusCode());
        }
        return "";
    }

    /**
     * 根据TAiread获取识别结果
     * @param aireadModel
     * @return
     * @throws IllegalAccessException
     */
    public AiIdenMap getWaterResultByAiread(TAireadModel aireadModel) throws IllegalAccessException {
        AiMeterParmModel model=new AiMeterParmModel();
        try{
            List<TAicbqCfgModel> cfgList = tAicbqCfgService.findTAicbqCfg(aireadModel.getDeviceSn(),"","1");
            TAicbqCfgModel cfgModel=null;
            if(cfgList!=null&&cfgList.size()>0){
                cfgModel=cfgList.get(0);

                //设置字体颜色,默认是1,白底黑字 2022-08-16 guozhao
                //Integer fontStyle= StringUtils.isEmpty(cfgModel.getMeterFontStyle())?1:Integer.valueOf(cfgModel.getMeterFontStyle());
                //model.setMeter_font_style(fontStyle);

                //字体颜色改为从站点台账中获取 2022-09-16 guozhao

                Integer fontStyle=1;
                StationAccModel accModel = stationAccService.findStationAccByStationCode(aireadModel.getStationCode());
                if(accModel!=null&& StringUtils.isNotEmpty(accModel.getMeterFontStyle())){
                    fontStyle=Integer.valueOf(accModel.getMeterFontStyle());
                }
                model.setMeter_font_style(fontStyle);
                model.setNum_numbers(cfgModel.getDigitNum());
                var dntype = DnType.getElement(cfgModel.getDnType());
                if(dntype!=null){
                    model.setMeter_type(dntype.getType());
                }
                var unit=UnitType.getElement(cfgModel.getUnitType());
                if(unit!=null){
                    int num=cfgModel.getUnitType()>4?4:cfgModel.getUnitType();
                    BigDecimal unitValue=new BigDecimal(unit.getValue());
                    unitValue=unitValue.setScale(4-num, RoundingMode.DOWN);
                    model.setUnit_number(unitValue);
                }
            }else {
                //没有历史配置,不做识别,不然会影响数据清洗的准确性  2022-07-23 guozhao
                AiIdenMap aiIdenMap=new AiIdenMap();
                aiIdenMap.setCode("NOCFG");
                return aiIdenMap;
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        /*if(!io.netty.util.internal.StringUtil.isNullOrEmpty(aireadModel.getPreAmount()))
        {
            model.setLast_value(new BigDecimal(aireadModel.getPreAmount()));
            if(aireadModel.getPreTime()!=null){
                model.setLast_value_time(DateUtil.formateDate(aireadModel.getPreTime(),"yyyy-MM-dd HH:mm:ss.SSS"));
            }
            else {
                model.setLast_value_time(DateUtil.getCurrentTime("yyyy-MM-dd HH:mm:ss.SSS"));
            }
        }
        else
        {
            //当前记录中没有上次识别值,去库中查询
            TAireadModel preModel = tAireadService.findPreGoodModelByDeviceSn(aireadModel.getDeviceSn());
            if(preModel!=null){
                BigDecimal lastValue=aireadModel.getIdentValue();
                String tsxx=aireadModel.getSzsbz();
                if(StringUtil.isEmpty(tsxx)){
                    //上次值没有调试信息,做识别
                    AiIdenMap aiIdenMap=new AiIdenMap();
                    aiIdenMap.setCode("NODEBUG");
                    return aiIdenMap;
                }
                else {
                    String[] arrTsxx=tsxx.split(",");
                    if(arrTsxx.length==12){
                        if(!NumberUtils.isDigits(arrTsxx[11])){
                            log.info("[服务侧识别]调试信息错误:"+tsxx);
                            AiIdenMap aiIdenMap=new AiIdenMap();
                            aiIdenMap.setCode("DEBUGNOTNUM");
                            return aiIdenMap;
                        }
                        //下面是要把调试信息的1278的信息,拼到IdentValue小数点后(要根据设备的尾数单位处理)
                        BigDecimal flag=new BigDecimal(arrTsxx[11]);
                        if(flag.compareTo(new BigDecimal(9))>0){
                            flag=flag.multiply(new BigDecimal(0.1));                //调试信息是两位的
                        }
                        int unit=cfgModel.getUintType()>4?4:cfgModel.getUintType();     //只处理有小数位的
                        int ptLen=4-unit+arrTsxx[11].length();

                        BigDecimal point=new BigDecimal(Math.pow(0.1,5-unit)).multiply(flag);
                        lastValue=lastValue.add(point);
                        lastValue=lastValue.setScale(ptLen, RoundingMode.DOWN);
                    }
                    else if(arrTsxx.length==10) {
                        //调试信息是10位,代表IdentValue中已经有调试信息了
                        lastValue= lastValue.setScale(5, RoundingMode.DOWN);
                    }
                }
                model.setLast_value(lastValue);
                String time=DateUtil.formateDate(preModel.getSampleTime(),"yyyy-MM-dd HH:mm:ss.SSS");
                model.setLast_value_time(time);
                model.setIs_app(false);
            }
            else {
                //上次值没有调试信息,做识别
                AiIdenMap aiIdenMap=new AiIdenMap();
                aiIdenMap.setCode("NOLAST");
                return aiIdenMap;
                //model.setIs_app(true);                  //如果没有上次的读数信息,用APP模式
            }
        }*/

        model.setIs_app(true);              //商定服务器侧不做水量判断 2022-07-24 guozhao
        model.setDevice_id(aireadModel.getDeviceSn());

        //优先使用大图  2022-08-17 guozhao
        if(StringUtils.isNotEmpty(aireadModel.getBigJpgUrl())){
            model.setImage_file(aireadModel.getBigJpgUrl());
        }else {
            model.setImage_file(aireadModel.getSmallJpgUrl());
        }

        return getWaterResult(model);
    }

    /**
     * http转服务器本地路径
     * @param url
     * @return
     */
    private String getImageLocalPath(String url){
        if(url.contains("http")){
            String src=env.getProperty(ResourceTag.ResourceUrlTag.getTag())+ ResourcePath.Image.getPath();
            String tar=env.getProperty(ResourceTag.UploadPathTag.getTag());
            return url.replaceAll(src,tar);
        }
        return url;
    }
}
