package com.haha.admin.task;

import com.haha.entity.InviteActivity;
import com.haha.service.InviteActivityService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 邀请活动定时任务
 * 负责自动更新活动状态、重试失败奖励、数据统计汇总等定时任务
 * 
 * 设计说明：所有数据库操作均通过 Service 层完成（而非直接调用 Mapper），
 * 以确保事务管理一致性，并遵循项目规范（参考 MarketingTask、CouponExpireTask）
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class InviteTask {

    private final InviteActivityService inviteActivityService;

    private static final AtomicInteger consecutiveConnectionFailures = new AtomicInteger(0);
    private static final int MAX_CONSECUTIVE_FAILURES = 5;

    @Scheduled(cron = "0 * * * * ?")
    public void updateActivityStatus() {
        if (!checkConnectionHealth()) {
            return;
        }
        log.info("[邀请定时任务] 开始执行活动状态更新任务");
        try {
            int[] result = inviteActivityService.autoUpdateActivityStatus();
            resetConnectionFailure();
            log.info("[邀请定时任务] 活动状态更新任务执行完成，开始{}个，结束{}个",
                     result[0], result[1]);
        } catch (CannotGetJdbcConnectionException e) {
            handleConnectionFailure("活动状态更新", e);
        } catch (Exception e) {
            log.error("[邀请定时任务] 活动状态更新任务执行失败", e);
        }
    }

    @Scheduled(cron = "0 */30 * * * ?")
    public void retryFailedRewards() {
        if (!checkConnectionHealth()) {
            return;
        }
        log.info("[邀请定时任务] 开始执行失败奖励重试任务");
        try {
            int[] result = inviteActivityService.retryFailedRewards(3, 50);
            resetConnectionFailure();
            log.info("[邀请定时任务] 失败奖励重试任务执行完成，成功{}个，失败{}个",
                     result[0], result[1]);
        } catch (CannotGetJdbcConnectionException e) {
            handleConnectionFailure("失败奖励重试", e);
        } catch (Exception e) {
            log.error("[邀请定时任务] 失败奖励重试任务执行失败", e);
        }
    }

    @Scheduled(cron = "0 0 1 * * ?")
    public void summarizeDailyStatistics() {
        if (!checkConnectionHealth()) {
            return;
        }
        log.info("[邀请定时任务] 开始执行每日数据汇总统计任务");
        try {
            LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
            LocalDateTime startOfDay = yesterday.toLocalDate().atStartOfDay();
            LocalDateTime endOfDay = yesterday.toLocalDate().atTime(23, 59, 59);

            List<InviteActivity> ongoingActivities = inviteActivityService.getOngoingActivities();

            for (InviteActivity activity : ongoingActivities) {
                Map<String, Object> stats = inviteActivityService.getActivityStatistics(activity.getId());

                log.info("[邀请定时任务] 活动[{}]昨日统计 - 总邀请: {}, 有效邀请: {}",
                         activity.getActivityName(),
                         stats.get("totalInviteCount"),
                         stats.get("validInviteCount"));
            }

            resetConnectionFailure();
            log.info("[邀请定时任务] 每日数据汇总统计任务执行完成");
        } catch (CannotGetJdbcConnectionException e) {
            handleConnectionFailure("每日数据汇总统计", e);
        } catch (Exception e) {
            log.error("[邀请定时任务] 每日数据汇总统计任务执行失败", e);
        }
    }

    @Scheduled(cron = "0 0 10 * * ?")
    public void remindEndingActivities() {
        if (!checkConnectionHealth()) {
            return;
        }
        log.info("[邀请定时任务] 开始执行活动即将结束提醒任务");
        try {
            List<InviteActivity> endingSoon = inviteActivityService.getEndingSoonActivities(3);

            for (InviteActivity activity : endingSoon) {
                long daysLeft = java.time.Duration.between(LocalDateTime.now(), activity.getEndTime()).toDays();
                log.info("[邀请定时任务] 活动[{}]将在{}天后结束",
                         activity.getActivityName(), daysLeft);
            }

            if (!endingSoon.isEmpty()) {
                log.info("[邀请定时任务] 发现{}个即将结束的活动", endingSoon.size());
            }

            resetConnectionFailure();
        } catch (CannotGetJdbcConnectionException e) {
            handleConnectionFailure("活动即将结束提醒", e);
        } catch (Exception e) {
            log.error("[邀请定时任务] 活动即将结束提醒任务执行失败", e);
        }
    }

    private boolean checkConnectionHealth() {
        int failures = consecutiveConnectionFailures.get();
        if (failures >= MAX_CONSECUTIVE_FAILURES) {
            if (failures == MAX_CONSECUTIVE_FAILURES) {
                log.warn("[邀请定时任务] 数据库连续连接失败{}次，后续{}次执行将跳过以避免日志刷屏。"
                         + "待数据库恢复后将自动重置。",
                         MAX_CONSECUTIVE_FAILURES, MAX_CONSECUTIVE_FAILURES);
                consecutiveConnectionFailures.incrementAndGet();
            }
            return false;
        }
        return true;
    }

    private void handleConnectionFailure(String taskName, CannotGetJdbcConnectionException e) {
        int failures = consecutiveConnectionFailures.incrementAndGet();
        if (failures <= MAX_CONSECUTIVE_FAILURES) {
            log.error("[邀请定时任务] {}任务执行失败 - 数据库连接不可用 (连续第{}次)"
                     + "\n请检查: \n1. 数据库服务器 server.kuaiyuman.cn:3306 是否可达"
                     + "\n2. HikariCP连接池配置 (当前max=10, minIdle=3)"
                     + "\n3. 网络连接/防火墙设置",
                     taskName, failures, e);
        }
    }

    private void resetConnectionFailure() {
        if (consecutiveConnectionFailures.get() > 0) {
            int oldVal = consecutiveConnectionFailures.getAndSet(0);
            if (oldVal > MAX_CONSECUTIVE_FAILURES) {
                log.info("[邀请定时任务] 数据库连接已恢复，之前连续失败{}次", oldVal);
            }
        }
    }
}
