package com.liquidnet.service.platform.controller.kylin;


import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.facebody.model.v20191230.DetectPedestrianRequest;
import com.aliyuncs.facebody.model.v20191230.DetectPedestrianResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.kylin.dto.vo.KylinApiCameraDevicesVo;
import com.liquidnet.service.kylin.dto.vo.KylinCameraDeviceCallBackVo;
import com.liquidnet.service.kylin.dto.vo.KylinCameraDevicesVo;
import com.liquidnet.service.kylin.entity.KylinCamera;
import com.liquidnet.service.kylin.entity.KylinCameraRecord;
import com.liquidnet.service.kylin.mapper.KylinCameraMapper;
import com.liquidnet.service.kylin.mapper.KylinCameraRecordMapper;
import com.liquidnet.service.platform.utils.DataUtils;
import com.liquidnet.service.platform.utils.ObjectUtil;
import com.liquidnet.service.platform.utils.QueueUtils;
import com.liquidnet.service.platform.utils.ViapiFileUtilAdvance;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 人流量排队检测摄像头表 前端控制器
 * </p>
 *
 * @author jiangxiulong
 * @since 2022-01-10
 */
@Api(tags = "视频计算")
@Slf4j
@RestController
@RequestMapping("/camera")
public class KylinCameraController {

    @Value("${liquidnet.aliyun.oss.accessKeyId}")
    private String accessKeyId;
    @Value("${liquidnet.aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    @Autowired
    private KylinCameraMapper cameraMapper;
    @Autowired
    private KylinCameraRecordMapper recordMapper;

    @Autowired
    private DataUtils dataUtils;
    @Autowired
    private QueueUtils queueUtils;

    @PostMapping(value = "callBack", produces = "application/xml;charset=UTF-8")
    @ApiOperation("截图回调")
    public String callBack(
            @RequestBody String requestBody
    ) {
        try {
            log.info("接收截图回调请求：[requestBody={}]", requestBody);
            // TODO: 2022/1/10 jxltodo 验签

            ObjectMapper configure = JsonUtils.OM().configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
            KylinCameraDeviceCallBackVo backVo = configure.readValue(
                    requestBody,
                    new TypeReference<KylinCameraDeviceCallBackVo>() {
                    }
            );
            KylinCamera cameraDeviceInfo = dataUtils.getCameraDeviceInfo(backVo.getStreamName());
            this.getPersonNum(cameraDeviceInfo);
            return "success";
        } catch (Exception e) {
            log.error("截图回调Exception：[msg={}, e={}]", e.getMessage(), e);
            return "error";
        }
    }

    @GetMapping("describeDevices")
    @ApiOperation("获取设备列表")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "query", dataType = "Integer", name = "pageNum", value = "页码"),
            @ApiImplicitParam(type = "query", dataType = "Integer", name = "pageSize", value = "数量")
    })
    public ResponseDto describeDevices(
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize
    ) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("vs.cn-beijing.aliyuncs.com");
        request.setSysVersion("2018-12-12");
        request.setSysAction("DescribeDevices");
        // request.putQueryParameter("GroupId", "410751715516867255-cn-beijing");
        request.putQueryParameter("PageNum", String.valueOf(pageNum));
        request.putQueryParameter("PageSize", String.valueOf(pageSize));
        try {
            CommonResponse response = client.getCommonResponse(request);
            JsonNode devices = JsonUtils.fromJson(response.getData(), JsonNode.class).get("Devices");
            ObjectMapper configure = JsonUtils.OM().configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
            List<KylinCameraDevicesVo> kylinCameraDevicesVos = configure.readValue(JsonUtils.toJson(devices), new TypeReference<List<KylinCameraDevicesVo>>() {
            });

            // 删除的设备没处理 回调或者人工 或者delAll 删除的时候清掉人数
            List<String> fieldIds = new ArrayList<>();
            for (KylinCameraDevicesVo devicesVo : kylinCameraDevicesVos) {
                String gbId = devicesVo.getGbId();
                KylinCamera kylinCamera = cameraMapper.selectOne(
                        Wrappers.lambdaQuery(KylinCamera.class)
                                .eq(KylinCamera::getGbId, gbId)
                );
                JsonNode jsonNode = JsonUtils.fromJson(devicesVo.getDescription(), JsonNode.class);
                int siteType = jsonNode.get("siteType").asInt();
                String fieldId = jsonNode.get("fieldId").asText();
                fieldIds.add(fieldId);
                if (null == kylinCamera) {
                    kylinCamera = KylinCamera.getNew();
                    kylinCamera.setCameraId(IDGenerator.nextSnowId());
                    kylinCamera.setGbId(gbId);
                    kylinCamera.setStatus(devicesVo.getStatus());
                    kylinCamera.setSiteType(siteType);
                    kylinCamera.setFieldId(fieldId);
                    kylinCamera.setImgUrl("https://camera.zhengzai.tv/camera/live/".concat(gbId).concat(".jpg"));
                    cameraMapper.insert(kylinCamera);
                } else {
                    kylinCamera.setStatus(devicesVo.getStatus());
                    kylinCamera.setSiteType(siteType);
                    kylinCamera.setFieldId(fieldId);
                    kylinCamera.setUpdatedAt(LocalDateTime.now());
                    cameraMapper.update(
                            kylinCamera,
                            Wrappers.lambdaUpdate(KylinCamera.class).eq(KylinCamera::getGbId, gbId)
                    );
                }
                dataUtils.setCameraDeviceInfo(kylinCamera);
            }

            dataUtils.delCameraDevicesList();

            // kylin前端获取使用
            List<String> fieldIdsNew = fieldIds.stream().distinct().collect(Collectors.toList());
            for (String fieldId : fieldIdsNew) {
                List<KylinCamera> cameraList = cameraMapper.selectList(
                        Wrappers.lambdaQuery(KylinCamera.class)
                                .eq(KylinCamera::getFieldId, fieldId)
                );
                ArrayList<KylinApiCameraDevicesVo> kylinApiCameraDevicesVoArrayList = ObjectUtil.getKylinApiCameraDevicesVoArrayList();
                for (KylinCamera kylinCamera : cameraList) {
                    KylinApiCameraDevicesVo kylinApiCameraDevicesVo = KylinApiCameraDevicesVo.getNew().copy(kylinCamera);
                    kylinApiCameraDevicesVoArrayList.add(kylinApiCameraDevicesVo);
                }
                dataUtils.setCameraDevices(fieldId, kylinApiCameraDevicesVoArrayList);
            }

            return ResponseDto.success();
        } catch (ClientException | JsonProcessingException e) {
            log.error("获取设备列表Exception：[msg={}, e={}]", e.getMessage(), e);
            return ResponseDto.failure();
        }
    }

    @GetMapping(value = "detectPedestrian")
    @ApiOperation("人体识别")
    public ResponseDto detectPedestrian() {
        long startTime1 = System.currentTimeMillis();
        List<KylinCamera> cameraList = dataUtils.getCameraDevicesList();
        if (null == cameraList) {
            cameraList = cameraMapper.selectList(
                    Wrappers.lambdaQuery(KylinCamera.class)
                            .eq(KylinCamera::getStatus, "on")
            );
            dataUtils.setCameraDevicesList(cameraList);
        }
        long startTime2 = System.currentTimeMillis();
        log.info("人体识别-查询设备列表->耗时:{}", (startTime2 - startTime1) + "毫秒");
        if (!CollectionUtils.isEmpty(cameraList)) {
            for (KylinCamera kylinCamera : cameraList) {
                this.getPersonNum(kylinCamera);
            }
        }
        return ResponseDto.success();
    }

    private void getPersonNum(KylinCamera kylinCamera) {
        try {
            long startTime22 = System.currentTimeMillis();
            InputStream inputStream = ViapiFileUtilAdvance.buildInputStream(kylinCamera.getImgUrl());
            ViapiFileUtilAdvance fileUtils = ViapiFileUtilAdvance.getInstance(accessKeyId, accessKeySecret, "cn-beijing");
            String ossTempFileUrl = fileUtils.upload(inputStream);
            long startTime3 = System.currentTimeMillis();
            log.info("人体识别-upload->耗时:{}", (startTime3 - startTime22) + "毫秒");

            DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai", accessKeyId, accessKeySecret);
            IAcsClient client = new DefaultAcsClient(profile);
            DetectPedestrianRequest request = new DetectPedestrianRequest();
            request.setImageURL(ossTempFileUrl);
            DetectPedestrianResponse response = client.getAcsResponse(request);
            long startTime4 = System.currentTimeMillis();
            log.info("人体识别-client->耗时:{}", (startTime4 - startTime3) + "毫秒");

            List<DetectPedestrianResponse.Data.Element> elementList = response.getData().getElements();
            long count = elementList.stream().filter(r -> r.getScore() > 0.25).count();
            long count1 = elementList.stream().filter(r -> r.getScore() <= 0.25).count();
            log.info("人体识别-count1:{}", count1);
            long startTime5 = System.currentTimeMillis();
            KylinCameraRecord cameraRecord = KylinCameraRecord.getNew();
            cameraRecord.setCameraRecordId(IDGenerator.nextSnowId());
            cameraRecord.setCameraId(kylinCamera.getCameraId());
            cameraRecord.setPersonNum((int) count);
            recordMapper.insert(cameraRecord);

            /*LinkedList<String> sqls = CollectionUtil.linkedListString();
            LinkedList<Object[]> sqlsDataA = CollectionUtil.linkedListObjectArr();
            sqls.add(SqlMapping.get("kylin_camera_record.insert"));
            sqlsDataA.add(new Object[]{
                    IDGenerator.nextSnowId(), kylinCamera.getCameraId(), (int) count
            });
            queueUtils.sendMsgByRedis(MQConst.SweetQueue.SWEET_ANSWER_INSERT.getKey(),
                    SqlMapping.gets(sqls, sqlsDataA));*/

            long startTime6 = System.currentTimeMillis();
            log.info("人体识别-MapperInsert->耗时:{}", (startTime6 - startTime5) + "毫秒");

            dataUtils.setCameraDevicePersonNum(kylinCamera.getCameraId(), count);
        } catch (Exception e) {
            log.error("人体识别Exception：[msg={}, e={}]", e.getMessage(), e);
        }
    }

}
