package com.ycwl.basic.controller.viid;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.ycwl.basic.annotation.IgnoreLogReq;
import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.mapper.DeviceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.viid.entity.DeviceIdObject;
import com.ycwl.basic.model.viid.entity.FaceListObject;
import com.ycwl.basic.model.viid.entity.FaceObject;
import com.ycwl.basic.model.viid.entity.FacePositionObject;
import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
import com.ycwl.basic.model.viid.entity.SubImageInfoObject;
import com.ycwl.basic.model.viid.entity.SubImageList;
import com.ycwl.basic.model.viid.entity.SystemTimeObject;
import com.ycwl.basic.model.viid.req.FaceUploadReq;
import com.ycwl.basic.model.viid.req.ImageUploadReq;
import com.ycwl.basic.model.viid.req.KeepaliveReq;
import com.ycwl.basic.model.viid.req.RegisterReq;
import com.ycwl.basic.model.viid.req.UnRegisterReq;
import com.ycwl.basic.model.viid.resp.SystemTimeResp;
import com.ycwl.basic.model.viid.resp.VIIDBaseResp;
import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.task.DynamicTaskGenerator;
import com.ycwl.basic.utils.ImageUtils;
import com.ycwl.basic.utils.IpUtils;
import com.ycwl.basic.utils.SnowFlakeUtil;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.ycwl.basic.constant.StorageConstant.PHOTO_PATH;
import static com.ycwl.basic.constant.StorageConstant.VIID_FACE;

@IgnoreToken
@RestController
@Api(tags = "摄像头对接接口")
@RequestMapping("/VIID")
@Slf4j
public class ViidController {
    @Autowired
    private DeviceMapper deviceMapper;
    private static final String serverId = "00000000000000000001";
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private DeviceRepository deviceRepository;
    @Autowired
    private ScenicRepository scenicRepository;
    @Autowired
    private TaskFaceService taskFaceService;
    private final Map<Long, ThreadPoolExecutor> executors = new ConcurrentHashMap<>();
    @Autowired
    private ScenicService scenicService;

    private ThreadPoolExecutor getExecutor(Long scenicId) {
        return executors.computeIfAbsent(scenicId, k -> {
            ThreadFactory threadFactory = new ThreadFactoryBuilder()
                    .setNamePrefix("VIID-" + scenicId + "-t")
                    .build();
            return new ThreadPoolExecutor(
                    4, 1024, 0L, TimeUnit.MILLISECONDS,
                    new ArrayBlockingQueue<>(1024),
                    threadFactory);
        });
    }

    // region 注册注销基础接口
    /**
     * 注册接口
     *
     * @param req     注册的信息
     * @param request 请求
     * @return 返回
     */
    @RequestMapping(value = "/System/Register", method = RequestMethod.POST)
    public VIIDBaseResp register(@RequestBody RegisterReq req, HttpServletRequest request) {
        DeviceIdObject deviceIdObject = req.getRegisterObject();
        log.info("注册的设备信息：{}", deviceIdObject);
        // 保存设备注册时间
        String deviceId = deviceIdObject.getDeviceId();
        DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
        if (device == null) {
            device = new DeviceEntity();
            device.setName("未配置设备");
            device.setNo(deviceId);
            device.setOnline(1);
        }
        device.setKeepaliveAt(new Date());
        device.setIpAddr(IpUtils.getIpAddr(request));
        if (device.getId() != null) {
            deviceMapper.updateEntity(device);
        } else {
            device.setId(SnowFlakeUtil.getLongId());
            deviceMapper.addEntity(device);
            deviceRepository.clearDeviceCache(deviceId);
        }
        return new VIIDBaseResp(
                new ResponseStatusObject(serverId, "/VIID/System/Register", "0", "注册成功", sdfTime.format(new Date()))
        );
    }

    /**
     * 保活接口
     *
     * @param req     保活的设备信息
     * @param request 请求
     * @return 返回
     */
    @IgnoreLogReq
    @RequestMapping(value = "/System/Keepalive", method = RequestMethod.POST)
    public VIIDBaseResp keepalive(@RequestBody KeepaliveReq req, HttpServletRequest request) {
        DeviceIdObject keepaliveObject = req.getKeepaliveObject();
//        log.info("对方发送的心跳的信息：{}", keepaliveObject);

        String deviceId = keepaliveObject.getDeviceId();
        DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);

        // 判断设备状态
        if (device == null) {
            // 不存在设备就注册
            device = new DeviceEntity();
            device.setName("未配置设备");
            device.setNo(deviceId);
            device.setOnline(1);
            device.setKeepaliveAt(new Date());
            device.setIpAddr(IpUtils.getIpAddr(request));
            device.setId(SnowFlakeUtil.getLongId());
            deviceMapper.addEntity(device);
            deviceRepository.clearDeviceCache(deviceId);
        } else {
            deviceRepository.updateOnlineStatus(device.getId(), IpUtils.getIpAddr(request), 1, new Date());
        }
//        log.info("已经解析过的心跳信息：{}", keepaliveObject);

        return new VIIDBaseResp(
                new ResponseStatusObject(deviceId, "/VIID/System/Keepalive", "0", "保活", sdfTime.format(new Date()))
        );
    }

    /**
     * 注销设备
     *
     * @param req     参数
     * @return 返回
     */
    @RequestMapping(value = "/System/UnRegister", method = RequestMethod.POST)
    public VIIDBaseResp unRegister(@RequestBody UnRegisterReq req, HttpServletRequest request) {
        // 获取设备id
        DeviceIdObject unRegisterObject = req.getUnRegisterObject();
        String deviceId = unRegisterObject.getDeviceId();
        log.info("获取的注销的请求参数：{}", unRegisterObject);

        // 首先查询该设备是否存在
        DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceId);
        // 判断
        if (device != null) {
            deviceRepository.updateOnlineStatus(device.getId(), IpUtils.getIpAddr(request), 0, new Date());
        }
        return new VIIDBaseResp(
                new ResponseStatusObject(deviceId, "/VIID/System/UnRegister", "0", "注销成功", sdfTime.format(new Date()))
        );
    }

    /**
     * 校时接口
     *
     * @return 返回
     */
    @RequestMapping(value = "/System/Time", method = RequestMethod.GET)
    public SystemTimeResp time() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return new SystemTimeResp(
                new SystemTimeObject(serverId, "2", sdf.format(new Date()), TimeZone.getTimeZone("Asia/Shanghai").toString())
        );
    }

    // endregion

    @Autowired
    private FaceSampleMapper faceSampleMapper;

    private final SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");


    /**
     * 批量新增人脸
     */
    @RequestMapping(value = "/Faces", method = RequestMethod.POST)
    @IgnoreLogReq
    public VIIDBaseResp faces(@RequestBody FaceUploadReq req) {
        FaceListObject faceListObject = req.getFaceListObject();
        List<FaceObject> faceObject = faceListObject.getFaceObject();
        String faceId = null;
        // 遍历人脸列表
        for (FaceObject face : faceObject) {
            // 设置FaceId
            faceId = face.getFaceID();
            // 获取图片信息
            SubImageList subImageList = face.getSubImageList();
            // 判断人脸对象中的列表是否为空
            String deviceID = face.getDeviceID();
            DeviceEntity device = deviceRepository.getDeviceByDeviceNo(deviceID);
            if (device == null) {
                continue;
            }
            DeviceConfigEntity deviceConfig = deviceRepository.getDeviceConfig(device.getId());
            int viidMode = 0;
            if (deviceConfig != null && deviceConfig.getViidType() != null) {
                viidMode = deviceConfig.getViidType();
            }
            Date shotTime = null;
            if (StringUtils.isNotBlank(face.getShotTime())) {
                try {
                    shotTime = sdfTime.parse(face.getShotTime());
                } catch (ParseException e) {
                    log.warn("拍摄时间时间转换失败，使用当前时间。错误entity：{}", face);
                }
            }
            if (shotTime == null) {
                if (StringUtils.isNotBlank(face.getFaceAppearTime())) {
                    try {
                        shotTime = sdfTime.parse(face.getFaceAppearTime());
                    } catch (ParseException e) {
                        log.warn("拍摄时间时间转换失败，使用当前时间。错误entity：{}", face);
                    }
                }
            }
            if (shotTime == null) {
                shotTime = new Date();
            } else if (Math.abs(shotTime.getTime() - System.currentTimeMillis()) >  24 * 60 * 60 * 1000) {
                shotTime = new Date();
            }
            Long scenicId = device.getScenicId();
            if (scenicId == null) {
                continue;
            }
            IStorageAdapter scenicStorageAdapter = scenicService.getScenicStorageAdapter(scenicId);
            IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
            FacePositionObject facePosition = new FacePositionObject();
            facePosition.setLtY(face.getLeftTopY());
            facePosition.setLtX(face.getLeftTopX());
            facePosition.setRbY(face.getRightBtmY());
            facePosition.setRbX(face.getRightBtmX());
            if (ObjectUtil.isNotEmpty(subImageList) && CollUtil.isNotEmpty(subImageList.getSubImageInfoObject())) {
                if (viidMode == 0) {
                    // 遍历每个图片对象
                    // 先找到type14的图片
                    List<SubImageInfoObject> type14ImageList = subImageList.getSubImageInfoObject().stream().filter(subImage -> "14".equals(subImage.getType())).collect(Collectors.toList());
                    for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
                        // base64转换成MultipartFIle
                        MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
                        String ext = subImage.getFileFormat();
                        if (ext.equalsIgnoreCase("jpeg")) {
                            ext = "jpg";
                        }
                        IStorageAdapter adapter = StorageFactory.use("faces");
                        // Type=11 人脸
                        if (subImage.getType().equals("11")) {
                            // 上传oss
                            Long newFaceSampleId = SnowFlakeUtil.getLongId();
                            if (Integer.valueOf(1).equals(device.getStatus())) {
                                FaceSampleEntity faceSample = new FaceSampleEntity();
                                faceSample.setId(newFaceSampleId);
                                faceSample.setScenicId(scenicId);
                                faceSample.setDeviceId(device.getId());
                                faceSample.setStatus(0);
                                faceSample.setCreateAt(shotTime);
                                String url = adapter.uploadFile(file, VIID_FACE, UUID.randomUUID() + "." + ext);
                                faceSample.setFaceUrl(url);
                                faceSampleMapper.add(faceSample);
                                ThreadPoolExecutor executor = getExecutor(scenicId);
                                executor.execute(() -> {
                                    if (faceBodyAdapter != null) {
                                        taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
                                        AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
                                        if (addFaceResp != null) {
                                            faceSample.setScore(addFaceResp.getScore());
                                            faceSampleMapper.update(faceSample);
                                        }
                                    }
                                    if (deviceConfig != null && Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
                                        DynamicTaskGenerator.addTask(faceSample.getId());
                                    }
                                });
                            }

                            for (SubImageInfoObject _subImage : type14ImageList) {
                                facePosition.setImgHeight(_subImage.getHeight());
                                facePosition.setImgWidth(_subImage.getWidth());
                                SourceEntity source = new SourceEntity();
                                source.setId(SnowFlakeUtil.getLongId());
                                source.setDeviceId(device.getId());
                                source.setScenicId(device.getScenicId());
                                source.setFaceSampleId(newFaceSampleId);
                                source.setCreateTime(shotTime);
                                source.setType(2);
                                // 上传oss
                                MultipartFile _file = ImageUtils.base64ToMultipartFile(_subImage.getData());
                                String filename = StorageUtil.joinPath(PHOTO_PATH, UUID.randomUUID() + "." + ext);
                                String _sourceUrl = scenicStorageAdapter.uploadFile(_file, filename);
                                scenicStorageAdapter.setAcl(StorageAcl.PUBLIC_READ, filename);
                                source.setUrl(_sourceUrl);
                                source.setPosJson(JSON.toJSONString(facePosition));
                                sourceMapper.add(source);
                            }
                            log.info("人脸信息及原图{}张入库成功！设备ID：{}", type14ImageList.size(), deviceID);
                        }
                    }
                } else if (viidMode == 1) {
                    for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
                        // base64转换成MultipartFIle
                        MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
                        String ext = subImage.getFileFormat();
                        if (ext.equalsIgnoreCase("jpeg")) {
                            ext = "jpg";
                        }
                        IStorageAdapter adapter = StorageFactory.use("faces");
                        // Type=14 人脸，传™的，有这么传的嘛
                        if (subImage.getType().equals("14")) {
                            // 上传oss
                            if (Integer.valueOf(1).equals(device.getStatus())) {
                                FaceSampleEntity faceSample = new FaceSampleEntity();
                                Long newFaceSampleId = SnowFlakeUtil.getLongId();
                                faceSample.setId(newFaceSampleId);
                                faceSample.setScenicId(scenicId);
                                faceSample.setDeviceId(device.getId());
                                faceSample.setStatus(0);
                                faceSample.setCreateAt(shotTime);
                                String url = adapter.uploadFile(file, VIID_FACE, UUID.randomUUID() + "." + ext);
                                faceSample.setFaceUrl(url);
                                faceSampleMapper.add(faceSample);
                                DynamicTaskGenerator.addTask(faceSample.getId());
                                ThreadPoolExecutor executor = getExecutor(scenicId);
                                executor.execute(() -> {
                                    if (faceBodyAdapter != null) {
                                        taskFaceService.assureFaceDb(faceBodyAdapter, scenicId.toString());
                                        AddFaceResp addFaceResp = faceBodyAdapter.addFace(scenicId.toString(), faceSample.getId().toString(), url, newFaceSampleId.toString());
                                        if (addFaceResp != null) {
                                            faceSample.setScore(addFaceResp.getScore());
                                            faceSampleMapper.update(faceSample);
                                        }
                                    }
                                    if (Integer.valueOf(1).equals(deviceConfig.getEnablePreBook())) {
                                        DynamicTaskGenerator.addTask(faceSample.getId());
                                    }
                                });
                                log.info("模式1人脸信息入库成功！设备ID：{}", deviceID);
                            }
                        }
                    }
                }
            }
        }

        return new VIIDBaseResp(
                new ResponseStatusObject(faceId, "/VIID/Faces", "0", "OK", sdfTime.format(new Date()))
        );
    }

    @RequestMapping(value = "/Images", method = RequestMethod.POST)
    @IgnoreLogReq
    public VIIDBaseResp images(HttpServletRequest request, @RequestBody ImageUploadReq req) throws IOException {
        return new VIIDBaseResp(
                new ResponseStatusObject("1", "/VIID/Images", "0", "OK", sdfTime.format(new Date()))
        );
    }

}
