package com.yimeng.okr.schedule;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yimeng.okr.entity.AssessmentPeriod;
import com.yimeng.okr.entity.KrKeyResult;
import com.yimeng.okr.entity.OkrObjective;
import com.yimeng.okr.entity.SysUser;
import com.yimeng.okr.enums.PeriodStatus;
import com.yimeng.okr.event.NotificationEvent;
import com.yimeng.okr.mapper.AssessmentPeriodMapper;
import com.yimeng.okr.mapper.KrKeyResultMapper;
import com.yimeng.okr.mapper.OkrObjectiveMapper;
import com.yimeng.okr.mapper.SysUserMapper;
import com.yimeng.okr.service.AssessmentPeriodService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class PeriodScheduler {

    private final AssessmentPeriodService periodService;
    private final AssessmentPeriodMapper periodMapper;
    private final SysUserMapper userMapper;
    private final OkrObjectiveMapper objectiveMapper;
    private final KrKeyResultMapper krMapper;
    private final ApplicationEventPublisher publisher;

    @Scheduled(cron = "0 0 2 * * ?")
    public void autoAdvancePeriods() {
        log.info("Running period auto-advance check...");
        periodService.checkAndAutoAdvance();
    }

    @Scheduled(cron = "0 0 10 * * ?")
    public void checkPeriodDeadlines() {
        log.info("Checking period deadlines...");
        List<AssessmentPeriod> periods = periodMapper.selectList(
                new LambdaQueryWrapper<AssessmentPeriod>()
                        .eq(AssessmentPeriod::getStatus, PeriodStatus.EXECUTING));
        LocalDate today = LocalDate.now();
        for (AssessmentPeriod p : periods) {
            try {
                if (ChronoUnit.DAYS.between(today, p.getEndDate()) == 3) {
                    List<SysUser> users = userMapper.selectList(null);
                    for (SysUser u : users) {
                        publisher.publishEvent(new NotificationEvent(
                                this, u.getId(), "PERIOD_DEADLINE",
                                "周期即将结束", "考核周期「" + p.getName() + "」将于3天后结束",
                                "period", p.getId()));
                    }
                }
            } catch (Exception e) {
                log.warn("Failed to check deadline for period {}: {}", p.getId(), e.getMessage());
            }
        }
    }

    @Scheduled(cron = "0 7 10 * * ?")
    public void checkKrLagging() {
        log.info("Checking KR lagging...");
        List<AssessmentPeriod> periods = periodMapper.selectList(
                new LambdaQueryWrapper<AssessmentPeriod>()
                        .eq(AssessmentPeriod::getStatus, PeriodStatus.EXECUTING));
        LocalDate today = LocalDate.now();
        for (AssessmentPeriod p : periods) {
            try {
                long totalDays = ChronoUnit.DAYS.between(p.getStartDate(), p.getEndDate());
                if (totalDays <= 0) continue;
                long elapsedDays = ChronoUnit.DAYS.between(p.getStartDate(), today);
                if (elapsedDays < 3) continue; // ignore first 3 days
                double elapsedRatio = Math.min(1.0, (double) elapsedDays / totalDays);
                double expectedProgress = elapsedRatio * 100;

                List<OkrObjective> objectives = objectiveMapper.selectList(
                        new LambdaQueryWrapper<OkrObjective>()
                                .eq(OkrObjective::getPeriodId, p.getId())
                                .eq(OkrObjective::getStatus, "APPROVED"));
                for (OkrObjective obj : objectives) {
                    List<KrKeyResult> krs = krMapper.selectList(
                            new LambdaQueryWrapper<KrKeyResult>()
                                    .eq(KrKeyResult::getObjectiveId, obj.getId()));
                    for (KrKeyResult kr : krs) {
                        if ("COMPLETED".equals(kr.getStatus())) continue;
                        double actualProgress = kr.getTargetValue() > 0
                                ? (kr.getCurrentValue() / kr.getTargetValue()) * 100 : 0;
                        if (actualProgress < expectedProgress - 20) {
                            publisher.publishEvent(new NotificationEvent(
                                    this, obj.getUserId(), "KR_LAGGING",
                                    "KR 进度滞后",
                                    "「" + kr.getTitle() + "」进度落后于时间线（当前 "
                                            + Math.round(actualProgress) + "%，预期 " + Math.round(expectedProgress) + "%），请及时更新",
                                    "objective", obj.getId()));
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("Failed to check KR lagging for period {}: {}", p.getId(), e.getMessage());
            }
        }
    }
}
