import { GameRemizerBot } from "./gameRemizerBotService.ts";
import { db } from "../db.ts";
import { allGames } from "../../drizzle/schema.ts";

export interface RemixScheduleConfig {
  enabled: boolean;
  frequency: "daily" | "weekly" | "monthly";
  dayOfWeek?: number; // 0-6 for weekly
  timeOfDay: string; // HH:MM format
  gamesPerRun: number;
  themes: string[];
  autoDeployApproved: boolean;
}

export interface RemixScheduleJob {
  id: string;
  name: string;
  status: "scheduled" | "running" | "completed" | "failed";
  lastRun?: Date;
  nextRun: Date;
  config: RemixScheduleConfig;
}

/**
 * Batch Remix Scheduler - Automates game creation on a schedule
 */
export class BatchRemixScheduler {
  private static jobs: Map<string, RemixScheduleJob> = new Map();
  private static timers: Map<string, NodeJS.Timeout> = new Map();

  /**
   * Create a new remix schedule
   */
  static createSchedule(
    name: string,
    config: RemixScheduleConfig,
    userId: number
  ): RemixScheduleJob {
    const jobId = `schedule-${Date.now()}`;
    const nextRun = this.calculateNextRun(config);

    const job: RemixScheduleJob = {
      id: jobId,
      name,
      status: "scheduled",
      nextRun,
      config,
    };

    this.jobs.set(jobId, job);
    this.scheduleJob(jobId, config);

    console.log(`✅ Remix schedule created: ${name} (Job ID: ${jobId})`);
    return job;
  }

  /**
   * Calculate next run time based on schedule config
   */
  private static calculateNextRun(config: RemixScheduleConfig): Date {
    const now = new Date();
    const [hours, minutes] = config.timeOfDay.split(":").map(Number);

    let nextRun = new Date(now);
    nextRun.setHours(hours, minutes, 0, 0);

    // If time has already passed today, schedule for next period
    if (nextRun <= now) {
      if (config.frequency === "daily") {
        nextRun.setDate(nextRun.getDate() + 1);
      } else if (config.frequency === "weekly") {
        nextRun.setDate(nextRun.getDate() + 7);
      } else if (config.frequency === "monthly") {
        nextRun.setMonth(nextRun.getMonth() + 1);
      }
    }

    return nextRun;
  }

  /**
   * Schedule a job to run at specified time
   */
  private static scheduleJob(jobId: string, config: RemixScheduleConfig): void {
    if (!config.enabled) return;

    const job = this.jobs.get(jobId);
    if (!job) return;

    const now = new Date();
    const timeUntilRun = job.nextRun.getTime() - now.getTime();

    // Clear existing timer if any
    if (this.timers.has(jobId)) {
      clearTimeout(this.timers.get(jobId));
    }

    // Schedule the job
    const timer = setTimeout(() => {
      this.executeRemixJob(jobId);
    }, Math.max(0, timeUntilRun));

    this.timers.set(jobId, timer);

    console.log(
      `⏰ Remix job scheduled: ${job.name} at ${job.nextRun.toISOString()}`
    );
  }

  /**
   * Execute a remix job
   */
  private static async executeRemixJob(jobId: string): Promise<void> {
    const job = this.jobs.get(jobId);
    if (!job) return;

    job.status = "running";
    this.jobs.set(jobId, job);

    console.log(`🎮 Starting remix job: ${job.name}`);

    try {
      // Select random themes from config
      const selectedThemes = job.config.themes.slice(
        0,
        Math.ceil(job.config.themes.length / 4)
      );

      for (const theme of selectedThemes) {
        try {
          // Start remix job for this theme
          const remixJob = await GameRemizerBot.startRemixJob(
            theme,
            job.config.gamesPerRun,
            0 // System user
          );

          console.log(`✅ Remix job started for theme: ${theme}`);

          // Wait for job to complete
          await this.waitForJobCompletion(remixJob.id);
        } catch (error) {
          console.error(`❌ Error remixing theme ${theme}:`, error);
        }
      }

      job.status = "completed";
      job.lastRun = new Date();
      job.nextRun = this.calculateNextRun(job.config);

      console.log(`✅ Remix job completed: ${job.name}`);
    } catch (error) {
      job.status = "failed";
      console.error(`❌ Remix job failed: ${job.name}`, error);
    }

    this.jobs.set(jobId, job);

    // Reschedule for next run
    this.scheduleJob(jobId, job.config);
  }

  /**
   * Wait for a remix job to complete
   */
  private static async waitForJobCompletion(
    jobId: string,
    maxWaitTime: number = 300000 // 5 minutes
  ): Promise<void> {
    const startTime = Date.now();

    while (Date.now() - startTime < maxWaitTime) {
      const job = GameRemizerBot.getJobStatus(jobId);
      if (job?.status === "completed" || job?.status === "failed") {
        return;
      }
      await new Promise((resolve) => setTimeout(resolve, 5000)); // Check every 5 seconds
    }
  }

  /**
   * Get all scheduled jobs
   */
  static getAllSchedules(): RemixScheduleJob[] {
    return Array.from(this.jobs.values());
  }

  /**
   * Get schedule by ID
   */
  static getSchedule(jobId: string): RemixScheduleJob | null {
    return this.jobs.get(jobId) || null;
  }

  /**
   * Update schedule config
   */
  static updateSchedule(
    jobId: string,
    config: Partial<RemixScheduleConfig>
  ): RemixScheduleJob | null {
    const job = this.jobs.get(jobId);
    if (!job) return null;

    job.config = { ...job.config, ...config };
    job.nextRun = this.calculateNextRun(job.config);

    this.jobs.set(jobId, job);
    this.scheduleJob(jobId, job.config);

    return job;
  }

  /**
   * Delete schedule
   */
  static deleteSchedule(jobId: string): boolean {
    if (this.timers.has(jobId)) {
      clearTimeout(this.timers.get(jobId));
      this.timers.delete(jobId);
    }
    return this.jobs.delete(jobId);
  }

  /**
   * Get scheduler statistics
   */
  static getStats() {
    const jobs = Array.from(this.jobs.values());
    const enabled = jobs.filter((j) => j.config.enabled).length;
    const scheduled = jobs.filter((j) => j.status === "scheduled").length;
    const running = jobs.filter((j) => j.status === "running").length;
    const completed = jobs.filter((j) => j.status === "completed").length;

    return {
      totalSchedules: jobs.length,
      enabled,
      scheduled,
      running,
      completed,
      nextScheduledRun: jobs
        .filter((j) => j.config.enabled)
        .sort((a, b) => a.nextRun.getTime() - b.nextRun.getTime())[0]?.nextRun,
    };
  }

  /**
   * Initialize default schedules
   */
  static initializeDefaultSchedules(): void {
    const defaultThemes = [
      "Underwater Adventure",
      "Space Odyssey",
      "Medieval Kingdom",
      "Tropical Paradise",
      "Cyberpunk Future",
      "Ancient Civilizations",
      "Enchanted Forest",
      "Wild West",
      "Asian Dragons",
      "Mystical Legends",
    ];

    // Weekly remix schedule
    const weeklyConfig: RemixScheduleConfig = {
      enabled: true,
      frequency: "weekly",
      dayOfWeek: 1, // Monday
      timeOfDay: "02:00", // 2 AM
      gamesPerRun: 10,
      themes: defaultThemes,
      autoDeployApproved: true,
    };

    this.createSchedule("Weekly Game Remix", weeklyConfig, 0);

    console.log("✅ Default remix schedules initialized");
  }
}

export default BatchRemixScheduler;
