package com.ycwl.basic.service.pc.impl;

import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.biz.TemplateBiz;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.enums.StatisticEnum;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.facebody.FaceBodyFactory;
import com.ycwl.basic.facebody.adapter.AliFaceBodyAdapter;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.StatisticsMapper;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.TemplateMapper;
import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.scenic.content.ContentPageVO;
import com.ycwl.basic.model.mobile.statistic.req.StatisticsRecordAddReq;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.face.req.FaceReqQuery;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
import com.ycwl.basic.model.pc.video.entity.VideoEntity;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.VideoRepository;
import com.ycwl.basic.repository.VideoTaskRepository;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.service.task.TaskService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.utils.StorageUtil;
import com.ycwl.basic.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;
import static com.ycwl.basic.constant.StorageConstant.USER_FACE;

/**
 * @Author：longbinbin
 * @Date：2024/12/2 16:39
 */
@Slf4j
@Service
public class FaceServiceImpl implements FaceService {
    @Autowired
    private FaceMapper faceMapper;
    @Autowired
    private TaskFaceService faceService;
    @Autowired
    private StatisticsMapper statisticsMapper;

    @Autowired
    private TaskService taskTaskService;
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private OrderBiz orderBiz;
    @Autowired
    private FaceRepository faceRepository;
    @Autowired
    private VideoMapper videoMapper;
    @Autowired
    private ScenicRepository scenicRepository;
    @Autowired
    private ScenicService scenicService;
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private VideoRepository videoRepository;
    @Autowired
    private VideoTaskRepository videoTaskRepository;
    @Autowired
    private TemplateBiz templateBiz;

    @Override
    public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
        PageHelper.startPage(faceReqQuery.getPageNum(),faceReqQuery.getPageSize());
        List<FaceRespVO> list = faceMapper.list(faceReqQuery);
        PageInfo<FaceRespVO> pageInfo = new PageInfo<>(list);
        return ApiResponse.success(pageInfo);
    }

    @Override
    public ApiResponse<List<FaceRespVO>> list(FaceReqQuery faceReqQuery) {
        return ApiResponse.success(faceMapper.list(faceReqQuery));
    }

    @Override
    public ApiResponse<FaceRespVO> getById(Long id) {
        return ApiResponse.success(faceMapper.getById(id));
    }

    @Override
    public ApiResponse<Integer> add(FaceEntity face) {
        face.setId(SnowFlakeUtil.getLongId());
        int i = faceMapper.add(face);
        if (i == 0) {
            return ApiResponse.fail("添加失败");
        }
        return ApiResponse.success(i);
    }

    @Override
    public ApiResponse<Integer> deleteById(Long id) {
        int i = faceMapper.deleteById(id);
        if (i == 0) {
            return ApiResponse.fail("删除失败");
        }
        return ApiResponse.success(i);
    }

    @Override
    public ApiResponse<Integer> deleteByIds(List<Long> ids) {
        int i = faceMapper.deleteByIds(ids);
        if (i == 0) {
            return ApiResponse.fail("删除失败");
        }
        return ApiResponse.success(i);
    }

    @Override
    public FaceRecognizeResp faceUpload(MultipartFile file, Long scenicId, Long userId) {
        //1、上传人脸照片
        IStorageAdapter adapter = StorageFactory.use("faces");
        String filePath = StorageUtil.joinPath(USER_FACE, DateUtil.format(new Date(),"yyyy-MM-dd"));
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.split("\\.", 2)[1];
        String fileName = UUID.randomUUID() + "." + suffix;
        String faceUrl = adapter.uploadFile(file, filePath, fileName);
        Long newFaceId = SnowFlakeUtil.getLongId();
        Long oldFaceId = null;
        IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(scenicId);
        faceService.assureFaceDb(faceBodyAdapter, USER_FACE_DB_NAME+scenicId);
        SearchFaceRespVo userDbSearchResult = faceService.searchFace(faceBodyAdapter, USER_FACE_DB_NAME+scenicId, faceUrl, "判断是否为用户上传过的人脸");
        float strictScore = 0.6F;
        if (userDbSearchResult == null) {
            // 都是null了，那得是新的
            faceBodyAdapter.addFace(USER_FACE_DB_NAME+scenicId, newFaceId.toString(), faceUrl, newFaceId.toString());
        } else if (userDbSearchResult.getSampleListIds() == null || userDbSearchResult.getSampleListIds().isEmpty()) {
            // 没有匹配到过，也得是新的
            faceBodyAdapter.addFace(USER_FACE_DB_NAME+scenicId, newFaceId.toString(), faceUrl, newFaceId.toString());
        } else if (userDbSearchResult.getFirstMatchRate() < strictScore) {
            // 有匹配结果，但是不匹配旧的
            faceBodyAdapter.addFace(USER_FACE_DB_NAME+scenicId, newFaceId.toString(), faceUrl, newFaceId.toString());
        } else {
            // 有匹配结果，且能匹配旧的数据
            Optional<Long> faceAny = userDbSearchResult.getSampleListIds().stream().filter(_faceId -> {
                FaceEntity face = faceRepository.getFace(_faceId);
                if (face == null) {
                    return false;
                }
                return face.getMemberId().equals(userId);
            }).findAny();
            if (faceAny.isPresent()) {
                oldFaceId = faceAny.get();
                FaceRespVO oldFace = faceMapper.getById(oldFaceId);
                if (oldFace == null) {
                    faceBodyAdapter.deleteFace(USER_FACE_DB_NAME+scenicId, oldFaceId.toString());
                    faceBodyAdapter.addFace(USER_FACE_DB_NAME+scenicId, newFaceId.toString(), faceUrl, newFaceId.toString());
                    oldFaceId = null;
                } else {
                    newFaceId = oldFaceId;
                }
            }
        }
        if (oldFaceId==null) {
            //新增人脸
            FaceEntity faceEntity = new FaceEntity();
            faceEntity.setCreateAt(new Date());
            faceEntity.setScenicId(scenicId);
            faceEntity.setMemberId(userId);
            faceEntity.setFaceUrl(faceUrl);
            faceEntity.setId(newFaceId);
            faceMapper.add(faceEntity);
        } else {
            //更新人脸
            FaceEntity faceEntity = new FaceEntity();
            faceEntity.setId(oldFaceId);
            faceEntity.setFaceUrl(faceUrl);
            faceMapper.update(faceEntity);
            faceRepository.clearFaceCache(oldFaceId);
        }
        StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
        statisticsRecordAddReq.setMemberId(userId);
        statisticsRecordAddReq.setType(StatisticEnum.UPLOAD_FACE.code);
        statisticsRecordAddReq.setScenicId(scenicId);
        statisticsRecordAddReq.setMorphId(newFaceId);
        statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
        FaceRecognizeResp resp = new FaceRecognizeResp();
        resp.setUrl(faceUrl);
        resp.setFaceId(newFaceId);
        matchFaceId(newFaceId, oldFaceId == null);
        return resp;
    }

    @Override
    public List<FaceRespVO> listByUser(Long userId, String scenicId) {
        return faceMapper.listByScenicAndUserId(scenicId, userId);
    }


    @Override
    public SearchFaceRespVo matchFaceId(Long faceId) {
        return matchFaceId(faceId, false);
    }

    @Override
    public SearchFaceRespVo matchFaceId(Long faceId, boolean isNew) {
        FaceEntity face = faceRepository.getFace(faceId);
        if (face == null) {
            return null;
        }
        ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
        IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(face.getScenicId());
        SearchFaceRespVo scenicDbSearchResult = faceService.searchFace(faceBodyAdapter, String.valueOf(face.getScenicId()), face.getFaceUrl(), "人脸识别");
        if (scenicDbSearchResult == null) {
            throw new BaseException("人脸识别失败，请换一张试试把~");
        }
        if (scenicDbSearchResult.getSampleListIds() != null && scenicDbSearchResult.getFirstMatchRate() != null && !scenicDbSearchResult.getSampleListIds().isEmpty()) {
            if (scenicConfig != null && scenicConfig.getFaceDetectHelperThreshold() != null && scenicConfig.getFaceDetectHelperThreshold() > 0) {
                if (scenicDbSearchResult.getSampleListIds().size() < scenicConfig.getFaceDetectHelperThreshold()) {
                    // 补救逻辑
                    Long resultItem = scenicDbSearchResult.getSampleListIds().getFirst();
                    FaceSampleEntity faceSample = faceRepository.getFaceSample(resultItem);
                    if (faceSample != null) {
                        // 以这个结果为人脸库的匹配结果
                        SearchFaceRespVo tmpResult = faceService.searchFace(faceBodyAdapter, String.valueOf(face.getScenicId()), faceSample.getFaceUrl(), "人脸补救措施1");
                        if (tmpResult != null && tmpResult.getSampleListIds() != null && !tmpResult.getSampleListIds().isEmpty()) {
                            scenicDbSearchResult = tmpResult;
                        }
                    }
                }
            }
        }
        FaceEntity faceEntity = new FaceEntity();
        faceEntity.setId(faceId);
        faceEntity.setScore(scenicDbSearchResult.getScore());
        faceEntity.setMatchResult(scenicDbSearchResult.getSearchResultJson());
        if (scenicDbSearchResult.getFirstMatchRate() != null) {
            faceEntity.setFirstMatchRate(BigDecimal.valueOf(scenicDbSearchResult.getFirstMatchRate()));
        }
        if (scenicDbSearchResult.getSampleListIds() != null) {
            faceEntity.setMatchSampleIds(scenicDbSearchResult.getSampleListIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
        }
        faceEntity.setCreateAt(new Date());
        faceEntity.setScenicId(face.getScenicId());
        faceEntity.setMemberId(face.getMemberId());
        faceEntity.setFaceUrl(face.getFaceUrl());
        List<Long> sampleListIds = scenicDbSearchResult.getSampleListIds();
        faceMapper.update(faceEntity);
        faceRepository.clearFaceCache(faceEntity.getId());
        if (sampleListIds != null && !sampleListIds.isEmpty()) {// 匹配原片：照片
            List<SourceEntity> sourceEntities = sourceMapper.listBySampleIds(sampleListIds);
            List<MemberSourceEntity> memberSourceEntityList = sourceEntities.stream().map(sourceEntity -> {
                MemberSourceEntity memberSourceEntity = new MemberSourceEntity();
                memberSourceEntity.setScenicId(face.getScenicId());
                memberSourceEntity.setFaceId(face.getId());
                memberSourceEntity.setMemberId(face.getMemberId());
                memberSourceEntity.setSourceId(sourceEntity.getId());
                memberSourceEntity.setType(sourceEntity.getType());
                IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), sourceEntity.getType(), faceEntity.getId());
                if (isBuy.isBuy()) { // 如果用户买过
                    memberSourceEntity.setIsBuy(1);
                } else if (isBuy.isFree()) { // 全免费逻辑
                    memberSourceEntity.setIsBuy(1);
                } else {
                    memberSourceEntity.setIsBuy(0);
                }
                return memberSourceEntity;
            }).collect(Collectors.toList());
            if (!memberSourceEntityList.isEmpty()) {
                sourceMapper.addRelations(memberSourceEntityList);
                taskTaskService.autoCreateTaskByFaceId(face.getId());
//                VideoPieceGetter.Task task = new VideoPieceGetter.Task();
//                task.faceId = face.getId();
//                task.faceSampleIds = sampleListIds;
//                task.memberId = face.getMemberId();
//                VideoPieceGetter.addTask(task);
            }
        }
        return scenicDbSearchResult;
    }

    @Override
    public ApiResponse<String> deleteFace(Long faceId) {
        FaceEntity face = faceRepository.getFace(faceId);
        faceMapper.deleteById(faceId);
        faceRepository.clearFaceCache(faceId);
        new Thread(() -> {
            sourceMapper.deleteNotBuyFaceRelation(face.getMemberId(), faceId);
            videoMapper.deleteNotBuyFaceRelations(face.getMemberId(), faceId);
            IFaceBodyAdapter adapter = scenicService.getScenicFaceBodyAdapter(face.getScenicId());
            adapter.deleteFace(USER_FACE_DB_NAME+face.getScenicId().toString(), faceId.toString());
        }).start();
        return ApiResponse.success("删除成功");
    }


    @Override
    public List<ContentPageVO> faceContentList(Long faceId) {
        FaceRespVO faceRespVO = faceMapper.getById(faceId);
        if (faceRespVO == null) {
            return Collections.emptyList();
        }
        Long userId = faceRespVO.getMemberId();
        List<ContentPageVO> contentList = templateMapper.listFor(faceRespVO.getScenicId());
        contentList.forEach(contentPageVO -> {
            List<MemberVideoEntity> memberVideoEntityList = videoMapper.userFaceTemplateVideo(userId, faceId, contentPageVO.getTemplateId());
            contentPageVO.setGoodsType(0);
            contentPageVO.setContentType(1);
            if (!memberVideoEntityList.isEmpty()) {
                contentPageVO.setIsBuy(memberVideoEntityList.getFirst().getIsBuy());
                contentPageVO.setContentId(memberVideoEntityList.getFirst().getVideoId());
                VideoEntity video = videoRepository.getVideo(contentPageVO.getContentId());
                if (video != null) {
                    contentPageVO.setDuration(video.getDuration());
                    contentPageVO.setLockType(-1);
                } else {
                    TaskEntity taskById = videoTaskRepository.getTaskById(memberVideoEntityList.getFirst().getTaskId());
                    if (taskById == null) {
                        contentPageVO.setLockType(0);
                    } else if (taskById.getStatus() == 3) {
                        contentPageVO.setLockType(2);
                    } else {
                        contentPageVO.setLockType(0);
                    }
                    contentPageVO.setContentType(0);
                }
            } else {
                contentPageVO.setContentType(0);
                boolean canGenerate = templateBiz.determineTemplateCanGenerate(contentPageVO.getTemplateId(), faceId);
                if (canGenerate) {
                    contentPageVO.setLockType(0);
                } else {
                    contentPageVO.setLockType(1);
                }
            }
        });

        SourceReqQuery sourceReqQuery = new SourceReqQuery();
        sourceReqQuery.setScenicId(faceRespVO.getScenicId());
        sourceReqQuery.setFaceId(faceId);
        sourceReqQuery.setMemberId(userId);
        //查询源素材
        List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery);
        ContentPageVO sourceVideoContent = new ContentPageVO();
        ContentPageVO sourceImageContent = new ContentPageVO();
        sourceVideoContent.setName("录像集");
        sourceImageContent.setName("照片集");
        sourceVideoContent.setScenicId(faceRespVO.getScenicId());
        sourceImageContent.setScenicId(faceRespVO.getScenicId());
        sourceVideoContent.setGoodsType(1);
        sourceImageContent.setGoodsType(2);
        sourceVideoContent.setContentType(2);
        sourceImageContent.setContentType(2);
        sourceVideoContent.setLockType(-1);
        sourceImageContent.setLockType(-1);
        ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
        if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceImage())) {
            IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, faceRespVO.getScenicId(), 2, faceId);
            sourceImageContent.setSourceType(isBuyRespVO.getGoodsType());
            sourceImageContent.setContentId(isBuyRespVO.getGoodsId());
            if (isBuyRespVO.isBuy()) {
                sourceImageContent.setIsBuy(1);
            } else {
                sourceImageContent.setIsBuy(0);
            }
            List<SourceEntity> sourceEntities = sourceMapper.listImageByFaceRelation(faceRespVO.getMemberId(), faceId);
            if (!sourceEntities.isEmpty()) {
                sourceImageContent.setLockType(-1);
            } else {
                sourceImageContent.setLockType(1);
            }
            contentList.add(sourceImageContent);
        }
        if (!Integer.valueOf(1).equals(scenicConfig.getDisableSourceVideo())) {
            IsBuyRespVO isBuyRespVO = orderBiz.isBuy(userId, faceRespVO.getScenicId(), 1, faceId);
            sourceVideoContent.setSourceType(isBuyRespVO.getGoodsType());
            sourceVideoContent.setContentId(isBuyRespVO.getGoodsId());
            if (isBuyRespVO.isBuy()) {
                sourceVideoContent.setIsBuy(1);
            } else {
                sourceVideoContent.setIsBuy(0);
            }
            List<SourceEntity> sourceEntities = sourceMapper.listVideoByFaceRelation(faceRespVO.getMemberId(), faceId);
            if (!sourceEntities.isEmpty()) {
                sourceVideoContent.setLockType(-1);
            } else {
                sourceVideoContent.setLockType(1);
            }
            contentList.add(sourceVideoContent);
        }
        sourceList.stream().collect(Collectors.groupingBy(SourceRespVO::getType)).forEach((type, list) -> {
            if (type == 1) {
                sourceVideoContent.setSourceType(1);
                sourceVideoContent.setLockType(-1);
                sourceVideoContent.setTemplateCoverUrl(list.getFirst().getUrl());
            } else {
                sourceImageContent.setSourceType(2);
                sourceImageContent.setLockType(-1);
                sourceImageContent.setTemplateCoverUrl(list.getFirst().getUrl());
            }
        });

        return contentList;
    }

    @Override
    public ApiResponse<List<ContentPageVO>> contentListUseDefaultFace() {
        FaceRespVO lastFaceByUserId = faceMapper.findLastFaceByUserId(BaseContextHandler.getUserId());
        List<ContentPageVO> contentPageVOS = faceContentList(lastFaceByUserId.getId());
        return ApiResponse.success(contentPageVOS);
    }


}
