import { Injectable, Logger } from "@nestjs/common";
import { Cron } from "@nestjs/schedule";
import { PrismaService } from "../database/prisma.service";
import {
  FINISHED_STATE_VALUES_FOR_DB,
  FINISHED_STATUS_VALUES_FOR_DB,
  LIVE_STATE_VALUES_FOR_DB,
  LIVE_STATUS_VALUES_FOR_DB,
} from "../common/utils/match-status.util";
import {
  getDateOnlyValueForTimeZone,
  getShiftedDateStringInTimeZone,
  getDayBoundsForTimeZone,
} from "../common/utils/timezone.util";
import { TaskLockService } from "./task-lock.service";

@Injectable()
export class LimitResetterTask {
  private readonly logger = new Logger(LimitResetterTask.name);
  private readonly timeZone = "Europe/Istanbul";

  constructor(
    private readonly prisma: PrismaService,
    private readonly taskLock: TaskLockService,
  ) {}

  private shouldSkipInHistoricalMode(jobName: string): boolean {
    if (process.env.FEEDER_MODE === "historical") {
      this.logger.debug(`Skipping ${jobName} in historical feeder mode`);
      return true;
    }
    return false;
  }

  /**
   * Reset usage limits daily at 03:00 (Europe/Istanbul)
   */
  @Cron("0 3 * * *", { timeZone: "Europe/Istanbul" })
  async resetUsageLimits() {
    if (this.shouldSkipInHistoricalMode("resetUsageLimits")) return;
    await this.taskLock.runWithLease(
      "resetUsageLimits",
      30 * 60 * 1000,
      async () => {
        this.logger.log("Starting daily usage limit reset job...");

        try {
          const today = getDateOnlyValueForTimeZone(this.timeZone);

          const result = await this.prisma.usageLimit.updateMany({
            where: {
              lastResetDate: { lt: today },
            },
            data: {
              analysisCount: 0,
              couponCount: 0,
              lastResetDate: today,
            },
          });

          if (result.count > 0) {
            this.logger.log(
              `Usage limits for ${result.count} users have been reset`,
            );
          } else {
            this.logger.log("No user limits needed resetting");
          }
        } catch (error: any) {
          this.logger.error(`Limit reset job failed: ${error.message}`);
        }
      },
      this.logger,
    );
  }

  /**
   * Clean up old predictions (older than 30 days)
   */
  @Cron("0 4 * * *", { timeZone: "Europe/Istanbul" })
  async cleanupOldData() {
    if (this.shouldSkipInHistoricalMode("cleanupOldData")) return;
    await this.taskLock.runWithLease(
      "cleanupOldData",
      60 * 60 * 1000,
      async () => {
        this.logger.log("Starting data cleanup job...");

        try {
          const thirtyDaysAgo = new Date();
          thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

          const deletedLogs = await this.prisma.aiPredictionsLog.deleteMany({
            where: {
              createdAt: { lt: thirtyDaysAgo },
            },
          });

          const yesterdayDate = getShiftedDateStringInTimeZone(
            -1,
            this.timeZone,
          );
          const { startMs: yesterdayStartMs } = getDayBoundsForTimeZone(
            yesterdayDate,
            this.timeZone,
          );
          const liveMatchCutoff = new Date(yesterdayStartMs);

          const deletedLiveMatches = await this.prisma.liveMatch.deleteMany({
            where: {
              updatedAt: { lt: liveMatchCutoff },
              OR: [
                { status: { in: FINISHED_STATUS_VALUES_FOR_DB } },
                { state: { in: FINISHED_STATE_VALUES_FOR_DB } },
                {
                  AND: [
                    { scoreHome: { not: null } },
                    { scoreAway: { not: null } },
                    {
                      NOT: {
                        OR: [
                          { status: { in: LIVE_STATUS_VALUES_FOR_DB } },
                          { state: { in: LIVE_STATE_VALUES_FOR_DB } },
                        ],
                      },
                    },
                  ],
                },
              ],
            },
          });

          this.logger.log(
            `Cleanup complete: ${deletedLogs.count} old logs, ${deletedLiveMatches.count} old live matches`,
          );
        } catch (error: any) {
          this.logger.error(`Cleanup job failed: ${error.message}`);
        }
      },
      this.logger,
    );
  }

  /**
   * Reset subscription status for expired users
   */
  @Cron("0 0 * * *", { timeZone: "Europe/Istanbul" })
  async checkSubscriptions() {
    if (this.shouldSkipInHistoricalMode("checkSubscriptions")) return;
    await this.taskLock.runWithLease(
      "checkSubscriptions",
      30 * 60 * 1000,
      async () => {
        this.logger.log("Checking expired subscriptions...");

        try {
          const now = new Date();

          const result = await this.prisma.user.updateMany({
            where: {
              subscriptionStatus: "active",
              subscriptionExpiresAt: { lt: now },
            },
            data: {
              subscriptionStatus: "expired",
            },
          });

          if (result.count > 0) {
            this.logger.log(`${result.count} subscriptions marked as expired`);
          }
        } catch (error: any) {
          this.logger.error(`Subscription check failed: ${error.message}`);
        }
      },
      this.logger,
    );
  }
}
