package org.jeecg.modules.xcx.clockin.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tencentcloudapi.iai.v20180301.models.VerifyFaceResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils2;
import org.jeecg.common.util.TencentUtils;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.modules.clockInproject.entity.ClockInProject;
import org.jeecg.modules.clockInproject.service.IClockInProjectService;
import org.jeecg.modules.clockInprojectitem.entity.ClockInProjectItem;
import org.jeecg.modules.clockInprojectitem.service.IClockInProjectItemService;
import org.jeecg.modules.clockIntimezone.entity.ClockInTimeZone;
import org.jeecg.modules.clockIntimezone.service.IClockInTimeZoneService;
import org.jeecg.modules.clockinconf.service.IClockInConfService;
import org.jeecg.modules.clockinlog.entity.ClockinLog;
import org.jeecg.modules.clockinlog.ressp.ClockInLogResp;
import org.jeecg.modules.clockinlog.service.IClockinLogService;
import org.jeecg.modules.clockinteam.entity.ClockinTeam;
import org.jeecg.modules.clockinteam.service.IClockinTeamService;
import org.jeecg.modules.clockinteamlog.entity.ClockinTeamLog;
import org.jeecg.modules.clockinteamlog.service.IClockinTeamLogService;
import org.jeecg.modules.hanHaiMember.entity.HanHaiMember;
import org.jeecg.modules.xcx.clockin.req.*;
import org.jeecg.modules.xcx.clockin.resp.ClockInTotalResp;
import org.jeecg.modules.xcx.clockin.service.IClockinService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
@Slf4j
@Service
public class ClockinServiceImpl implements IClockinService {
    @Resource
    private IClockinLogService clockinLogService;
    @Resource
    private ShiroRealm shiroRealm;
    @Resource
    private IClockinTeamService clockinTeamService;
    @Resource
    private IClockInProjectService clockInProjectService;
    @Resource
    private IClockInProjectItemService clockInProjectItemService;
    @Resource
    private IClockinTeamLogService clockinTeamLogService;
    @Resource
    private IClockInConfService clockInConfService;
    @Resource
    private IClockInTimeZoneService clockInTimeZoneService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<?> clockIn(ClockInReq clockInReq) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(clockInReq.getToken());
//        if(StringUtils.isBlank(clockInReq.getPic())){
//            throw new JeecgBootException("请拍照打卡");
//        }
        if(StringUtils.isBlank(clockInReq.getAddress()) || StringUtils.isBlank(clockInReq.getLon()) || StringUtils.isBlank(clockInReq.getLat())){
            throw new JeecgBootException("请打开定位打卡");
        }
        ClockinTeamLog clockinTeamLog = clockinTeamLogService.lambdaQuery()
                .eq(ClockinTeamLog::getDelFlag, 0)
                .eq(ClockinTeamLog::getUserId, hanHaiMember.getId())
                .one();
        if(clockinTeamLog == null){
            throw new JeecgBootException("未绑定团队，请先绑定团队");
        }
        ClockInProject clockInProject = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .eq(ClockInProject::getTeamId, clockinTeamLog.getTeamId())
                .one();
        if(clockInProject == null){
            throw new JeecgBootException("当前团队未配置项目，无需打卡");
        }
        Integer distance = clockInProjectService.getDistance(clockInReq.getLon(), clockInReq.getLat(), clockInProject.getId());
        if(distance > clockInProject.getDistance()){
            log.info("用户经度:"+clockInReq.getLon()+"纬度："+clockInReq.getLat());
            log.info("距离:"+distance);
            throw new JeecgBootException("不在有效打卡距离内");
        }
        ClockInTimeZone clockInTimeZone = clockInTimeZoneService.lambdaQuery()
                .eq(ClockInTimeZone::getId, clockInProject.getTimeZone())
                .one();
        String zonedDateTimeNow = DateUtils2.getZonedDateTimeNow(clockInTimeZone.getTimeZone());
        String zonedDateTimeNowYYYYMMDD = DateUtils2.getZonedDateTimeNowYYYYMMDD(clockInTimeZone.getTimeZone());
        Date date2 = DateUtils2.getDate(zonedDateTimeNowYYYYMMDD + " 23:59:59");
        LocalDateTime localDateTime2 = DateUtils2.dateToDateTime(date2);
        Integer type = 0;
        if(DayOfWeek.SATURDAY.equals(localDateTime2.getDayOfWeek()) || DayOfWeek.SUNDAY.equals(localDateTime2.getDayOfWeek())){
            type = 1;
        }
        ClockInProjectItem validClockInTime = clockInProjectItemService.getValidClockInTime(zonedDateTimeNow, clockInProject.getId(),type);
        if(validClockInTime == null){
            log.info("时间:"+zonedDateTimeNow+"项目id："+clockInProject.getId());
            throw new JeecgBootException("当前未到打卡时间");
        }



        ClockinLog clockinLog1 = clockinLogService.lambdaQuery()
                .eq(ClockinLog::getDelFlag, 0)
                .eq(ClockinLog::getProjectItemId, validClockInTime.getId())
                .eq(ClockinLog::getUserId,hanHaiMember.getId())
                .like(ClockinLog::getCreateTime, DateUtils2.getNowDateString4(clockInTimeZone.getTimeZone()))
                .one();
        ClockinLog clockinLog = new ClockinLog();
        if(clockinLog1 != null){
            clockinLog.setId(clockinLog1.getId());
        }

        clockinLog.setUserId(hanHaiMember.getId());
//        clockinLog.setPic(clockInReq.getPic());
        clockinLog.setAddress(clockInReq.getAddress());
        clockinLog.setLon(clockInReq.getLon());
        clockinLog.setLat(clockInReq.getLat());
        clockinLog.setProjectId(clockInProject.getId());
        clockinLog.setProjectItemId(validClockInTime.getId());
        clockinLog.setTeamId(clockinTeamLog.getTeamId());
        clockinLog.setType(validClockInTime.getType());
        ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(clockInTimeZone.getTimeZone()));
        LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        clockinLog.setClockInTime(date);
        clockinLogService.saveOrUpdate(clockinLog);
        return Result.OK();
    }

    @Override
    public Result<?> clockInLog(ClockInLogReq clockInLogReq) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(clockInLogReq.getToken());

        ClockinTeamLog clockinTeamLog = clockinTeamLogService.lambdaQuery()
                .eq(ClockinTeamLog::getDelFlag, 0)
                .eq(ClockinTeamLog::getUserId, hanHaiMember.getId())
                .one();
        ClockInProject clockInProject = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .eq(ClockInProject::getTeamId, clockinTeamLog.getTeamId())
                .one();
        ClockInTimeZone clockInTimeZone = clockInTimeZoneService.lambdaQuery()
                .eq(ClockInTimeZone::getId, clockInProject.getTimeZone())
                .one();

        if(StringUtils.isBlank(clockInLogReq.getDate())){
            clockInLogReq.setDate(DateUtils2.getZonedDateTimeNowYYYYMMDD(clockInTimeZone.getTimeZone()));
        }else{
            Date date = DateUtils2.getDate(clockInLogReq.getDate());
            String dateString = DateUtils2.getDateString(date, "yyyy-MM-dd");
            clockInLogReq.setDate(dateString);
        }

        Date date = DateUtils2.getDate(clockInLogReq.getDate() + " 23:59:59");
        LocalDateTime localDateTime = DateUtils2.dateToDateTime(date);
        Integer type = 0;
        if(DayOfWeek.SATURDAY.equals(localDateTime.getDayOfWeek()) || DayOfWeek.SUNDAY.equals(localDateTime.getDayOfWeek())){
            type = 1;
        }



//        List<ClockinLog> clockinLogList = clockinLogService.lambdaQuery()
//                .eq(ClockinLog::getDelFlag, 0)
//                .eq(ClockinLog::getUserId, hanHaiMember.getId())
//                .like(ClockinLog::getCreateTime, clockInLogReq.getDate())
//                .list();
        List<ClockInLogResp> clockInLogResp = clockinLogService.getClockInLogResp(clockInLogReq.getDate(), clockInProject.getId(), hanHaiMember.getId(),type);
        return Result.OK(clockInLogResp);
    }

    @Override
    public Result<?> clockInTotal(ClockInTotalReq clockInTotalReq) {
        Map<String, Object> map = new HashMap<>();
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(clockInTotalReq.getToken());
        ClockinTeamLog clockinTeamLog = clockinTeamLogService.lambdaQuery()
                .eq(ClockinTeamLog::getDelFlag, 0)
                .eq(ClockinTeamLog::getUserId, hanHaiMember.getId())
                .one();
        ClockInProject clockInProject = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .eq(ClockInProject::getTeamId, clockinTeamLog.getTeamId())
                .one();


        Date date = new Date();
        if(StringUtils.isNotBlank(clockInTotalReq.getDate())){
            date = DateUtils2.getDate(clockInTotalReq.getDate());
        }
        String nowDay2 = DateUtils2.getNowDay2(DateUtils2.currentXDayOfMonth(date));
        Integer n = Integer.parseInt(nowDay2);
        String yyyymm = DateUtils2.getYYYYMM(date);
        List<ClockInTotalResp> clockInTotalResps = new ArrayList<>();
        //正常
        Integer normal = 0;
        //缺卡
        Integer noCard = 0;
        //未打卡
        Integer abnormal = 0;
        Long todayDate = DateUtils2.getTodayTwelve();
        for (int i = 1;i <= n;i++){

            ClockInTotalResp clockInTotalResp = new ClockInTotalResp();
            String dd = i+"";
            if(i < 10){
                dd = "0"+i;
            }
            dd = "-"+dd;
            String yyyymmdd = yyyymm+dd;
            Long milliSecond = DateUtils2.getMilliSecond(yyyymmdd+" 23:59:59");
            if(milliSecond>todayDate){
                break;
            }

            Date date2 = DateUtils2.getDate(yyyymmdd + " 23:59:59");
            LocalDateTime localDateTime = DateUtils2.dateToDateTime(date2);
            Integer type = 0;
            if(DayOfWeek.SATURDAY.equals(localDateTime.getDayOfWeek()) || DayOfWeek.SUNDAY.equals(localDateTime.getDayOfWeek())){
                type = 1;
            }
            List<ClockInProjectItem> clockInProjectItemList = clockInProjectItemService.lambdaQuery()
                    .eq(ClockInProjectItem::getDelFlag, 0)
                    .eq(ClockInProjectItem::getType,type)
                    .eq(ClockInProjectItem::getProjectId, clockInProject.getId())
                    .list();
            Integer clockInTotal = clockinLogService.getClockInTotal(hanHaiMember.getId(), yyyymmdd);
            clockInTotalResp.setDate(yyyymmdd);

            if(clockInTotal == 0){


                    abnormal = abnormal+1;


                clockInTotalResp.setType(2);
            }else if(clockInTotal<clockInProjectItemList.size()){
                clockInTotalResp.setType(1);
                noCard = noCard+1;
            }else{
                clockInTotalResp.setType(0);
                normal = normal+1;
            }
            clockInTotalResp.setNum(clockInProjectItemList.size()-clockInTotal);
            clockInTotalResps.add(clockInTotalResp);
        }
        map.put("date",clockInTotalResps);
        map.put("normal",normal);
        map.put("noCard",noCard);
        map.put("abnormal",abnormal);
        return Result.OK(map);
    }

    @Override
    public Result<?> verifyFace(VerifyFaceReq verifyFaceReq) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(verifyFaceReq.getToken());

        VerifyFaceResponse verifyFaceResponse = TencentUtils.VerifyFace(hanHaiMember.getId(), verifyFaceReq.getImage(),Long.parseLong(clockInConfService.getConf("qualityControl")));
        if(!verifyFaceResponse.getIsMatch()){
            throw new JeecgBootException("人脸识别错误");
        }

        return Result.OK();
    }

    @Override
    public Result<?> clockInTime(ClockInTimeReq clockInTimeReq) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(clockInTimeReq.getToken());

        ClockinTeamLog clockinTeamLog = clockinTeamLogService.lambdaQuery()
                .eq(ClockinTeamLog::getDelFlag, 0)
                .eq(ClockinTeamLog::getUserId, hanHaiMember.getId())
                .one();
        if(clockinTeamLog == null){
            throw new JeecgBootException("未绑定团队，请先绑定团队");
        }
        ClockInProject clockInProject = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .eq(ClockInProject::getTeamId, clockinTeamLog.getTeamId())
                .one();
        if(clockInProject == null){
            throw new JeecgBootException("当前团队未配置项目");
        }
        ClockInTimeZone clockInTimeZone = clockInTimeZoneService.lambdaQuery()
                .eq(ClockInTimeZone::getId, clockInProject.getTimeZone())
                .one();
        String zonedDateTimeNow = DateUtils2.getZonedDateTimeNow(clockInTimeZone.getTimeZone());
        String zonedDateTimeNowYYYYMMDD = DateUtils2.getZonedDateTimeNowYYYYMMDD(clockInTimeZone.getTimeZone());
        Date date2 = DateUtils2.getDate(zonedDateTimeNowYYYYMMDD + " 23:59:59");
        LocalDateTime localDateTime2 = DateUtils2.dateToDateTime(date2);
        Integer type = 0;
        if(DayOfWeek.SATURDAY.equals(localDateTime2.getDayOfWeek()) || DayOfWeek.SUNDAY.equals(localDateTime2.getDayOfWeek())){
            type = 1;
        }
        ClockInProjectItem validClockInTime = clockInProjectItemService.getValidClockInTime(zonedDateTimeNow, clockInProject.getId(),type);
        if(validClockInTime == null){
            log.info("时间:"+zonedDateTimeNow+"项目id："+clockInProject.getId());
            throw new JeecgBootException("当前未到打卡时间");
        }

        Integer distance = clockInProjectService.getDistance(clockInTimeReq.getLon(), clockInTimeReq.getLat(), clockInProject.getId());
        log.info("用户经度:"+clockInTimeReq.getLon()+"纬度："+clockInTimeReq.getLat());
        log.info("距离:"+distance);
        if(distance > clockInProject.getDistance()){

            throw new JeecgBootException("不在有效打卡距离内");
        }

        return Result.OK();
    }

    @Override
    public Result<?> getProjectListPage(ProjectListPageReq projectListPageReq) {
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(projectListPageReq.getToken());

        if(hanHaiMember.getAdminFlag() == 0){
            throw new JeecgBootException("无权访问");
        }

        Page<ClockInProject> page = new Page<>(projectListPageReq.getPageNo(), projectListPageReq.getPageSize());

        Page<ClockInProject> clockInProjectPage = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .orderByDesc(ClockInProject::getCreateTime)
                .page(page);
        return Result.OK(clockInProjectPage);
    }

    @Override
    public Result<?> setProjectLocation(SetProjectLocationReq setProjectLocationReq) {

        if(StringUtils.isBlank(setProjectLocationReq.getLon())){
            throw new JeecgBootException("请上传经度");
        }
        if(StringUtils.isBlank(setProjectLocationReq.getLat())){
            throw new JeecgBootException("请上传纬度");
        }
        ClockInProject clockInProject = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .eq(ClockInProject::getId, setProjectLocationReq.getId())
                .one();
        if(clockInProject == null){
            throw new JeecgBootException("数据错误");
        }

        ClockInProject clockInProject1 = new ClockInProject();
        clockInProject1.setId(clockInProject.getId());
        clockInProject1.setLon(setProjectLocationReq.getLon());
        clockInProject1.setLat(setProjectLocationReq.getLat());
        clockInProjectService.updateById(clockInProject1);

        return Result.OK();
    }

    @Override
    public Result<?> getProjectById(String id) {
        ClockInProject clockInProject = clockInProjectService.lambdaQuery()
                .eq(ClockInProject::getDelFlag, 0)
                .eq(ClockInProject::getId, id)
                .one();
        return Result.OK(clockInProject);
    }
}
