/**
 * auto-scheduler.js — Cron scheduler untuk auto-refresh token
 * Cek pool setiap interval, jalankan bot jika semua token expired
 */

import cron from "node-cron";
import { runFullFlow, refreshExistingAccountToken, stopActiveBot } from "./auto-token.js";
import * as Accounts from "./account-store.js";

let schedulerTask = null;
let isRunning = false;
let lastRunResult = null;
let lastRunAt = null;
let nextRunAt = null;
let consecutiveFailures = 0;

/** Global SSE client registry */
const sseClients = new Set();

export function addSseClient(res) {
  sseClients.add(res);
  res.on("close", () => sseClients.delete(res));
}

export function broadcastLog(event) {
  const data = JSON.stringify(event);
  for (const res of sseClients) {
    try {
      res.write(`data: ${data}\n\n`);
    } catch {
      sseClients.delete(res);
    }
  }
}

/** Check if pool needs refresh (all expired or empty) */
function poolNeedsRefresh() {
  const accounts = Accounts.listAccountsSafe();
  if (accounts.length === 0) return true;
  const active = accounts.filter((a) => !a.expired);
  return active.length === 0;
}

/** Scan and login back into expired accounts with remaining runs */
async function reviveExpiredAccounts() {
  const accounts = Accounts.listAccounts();
  const toRevive = accounts.filter((a) => 
    (a.runs || 0) < 3 && 
    (Accounts.isExpired(a.token) || a.expired) &&
    a.email && a.password
  );

  if (toRevive.length === 0) return 0;

  broadcastLog({ type: "info", msg: `🔄 Menemukan ${toRevive.length} akun expired dengan sisa kuota. Mencoba login ulang...` });

  let revivedCount = 0;
  for (const acc of toRevive) {
    try {
      const result = await refreshExistingAccountToken(acc.id, acc.email, acc.password, (event) => broadcastLog(event));
      if (result.ok) {
        revivedCount++;
      }
    } catch (err) {
      broadcastLog({ type: "error", msg: `❌ Gagal revive akun ${acc.email}: ${err.message}` });
    }
  }
  return revivedCount;
}

/** Run the auto-token flow (protected from concurrent runs) */
export async function triggerAutoToken(force = false) {
  if (isRunning) {
    broadcastLog({ type: "warn", msg: "⚠️ Bot sudah berjalan, tunggu selesai dulu." });
    return { ok: false, error: "Already running" };
  }

  isRunning = true;
  lastRunAt = new Date().toISOString();
  broadcastLog({ type: "start", msg: "🤖 Auto Token Bot dimulai..." });

  try {
    // 1. Coba revive akun expired yang sisa kuotanya masih ada
    const revived = await reviveExpiredAccounts();
    if (revived > 0) {
      broadcastLog({ type: "success", msg: `🎉 Berhasil revive ${revived} akun dari pool!` });
    }

    // 2. Cek apakah setelah revive, pool masih butuh akun baru
    if (!force && !poolNeedsRefresh()) {
      broadcastLog({ type: "info", msg: "ℹ️ Pool sekarang memiliki akun aktif, selesai." });
      isRunning = false;
      consecutiveFailures = 0; // Reset on success
      lastRunResult = { ok: true, msg: "Pool revived successfully" };
      return lastRunResult;
    }

    // 3. Jika masih kosong, buat akun baru
    broadcastLog({ type: "info", msg: "⏳ Pool masih kosong/habis. Membuat akun baru..." });
    const result = await runFullFlow((event) => broadcastLog(event));
    lastRunResult = result;
    isRunning = false;
    
    if (result.ok) {
      consecutiveFailures = 0; // Reset on success
      broadcastLog({ type: "success", msg: `🎉 Selesai! Akun baru: ${result.label}` });
    } else {
      consecutiveFailures++;
      broadcastLog({ type: "error", msg: `❌ Gagal: ${result.error} (Gagal berturut-turut: ${consecutiveFailures}/3)` });
      if (consecutiveFailures >= 3) {
        broadcastLog({ type: "error", msg: "⚠️ Auto-Scheduler dihentikan otomatis karena gagal 3 kali berturut-turut." });
        stopScheduler();
      }
    }
    return result;
  } catch (err) {
    isRunning = false;
    consecutiveFailures++;
    lastRunResult = { ok: false, error: err.message };
    broadcastLog({ type: "error", msg: `❌ Error tak terduga: ${err.message} (Gagal berturut-turut: ${consecutiveFailures}/3)` });
    if (consecutiveFailures >= 3) {
      broadcastLog({ type: "error", msg: "⚠️ Auto-Scheduler dihentikan otomatis karena gagal 3 kali berturut-turut." });
      stopScheduler();
    }
    return lastRunResult;
  }
}

/** Start the cron scheduler */
export function startScheduler(intervalMinutes = 45) {
  stopScheduler();

  // Convert minutes to cron expression: every N minutes
  const cronExpr = `*/${intervalMinutes} * * * *`;
  broadcastLog({ type: "info", msg: `⏰ Scheduler dimulai: setiap ${intervalMinutes} menit` });

  schedulerTask = cron.schedule(cronExpr, async () => {
    nextRunAt = null;
    broadcastLog({ type: "info", msg: `⏰ Cron trigger: cek pool...` });
    await triggerAutoToken(false);
    // Set next run time
    nextRunAt = new Date(Date.now() + intervalMinutes * 60 * 1000).toISOString();
  });

  nextRunAt = new Date(Date.now() + intervalMinutes * 60 * 1000).toISOString();
  return cronExpr;
}

/** Stop the cron scheduler */
export function stopScheduler() {
  if (schedulerTask) {
    schedulerTask.destroy();
    schedulerTask = null;
    nextRunAt = null;
    broadcastLog({ type: "info", msg: "⏹️ Scheduler dihentikan." });
  }
}

export async function stopSchedulerBot() {
  broadcastLog({ type: "info", msg: "🛑 Menghentikan bot secara paksa..." });
  const res = await stopActiveBot();
  isRunning = false;
  broadcastLog({ type: "warn", msg: "⏹️ Bot berhasil dihentikan oleh admin." });
  return res;
}

export function getSchedulerStatus() {
  return {
    running: isRunning,
    schedulerActive: schedulerTask !== null,
    lastRunAt,
    nextRunAt,
    lastRunResult,
    poolNeedsRefresh: poolNeedsRefresh(),
    headless: process.env.PLAYWRIGHT_HEADLESS !== "false",
  };
}
