/**
 * auto-scheduler.js — Scheduler timer untuk auto-refresh token
 * Lebih stabil untuk interval custom dan lebih mudah dites daripada cron.
 */

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

let creatorTimer = null;
let creatorEnabled = false;
let creatorIntervalMinutes = 45;
let creatorNextRunAt = null;

let reviveTimer = null;
let reviveEnabled = false;
let reviveIntervalMinutes = 15;
let reviveNextRunAt = null;

let isRunning = false;
let lastRunResult = null;
let lastRunAt = null;
let consecutiveFailures = 0;
let testTimer = null;
let testRunAt = null;

/** 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) {
  for (const res of sseClients) {
    try {
      let filteredEvent = event;
      if (res.adminRole !== "owner") {
        if (event && typeof event === "object") {
          filteredEvent = JSON.parse(JSON.stringify(event));
          if (filteredEvent.msg && typeof filteredEvent.msg === "string") {
            filteredEvent.msg = filteredEvent.msg
              .replace(/https?:\/\/(?:www\.)?figma\.com/gi, "[masked]")
              .replace(/https?:\/\/weave\.figma\.com/gi, "[masked]")
              .replace(/figma\.com/gi, "[masked]")
              .replace(/weave\.figma\.com/gi, "[masked]")
              .replace(/figma/gi, "System")
              .replace(/weave/gi, "Engine");
          }
        }
      }
      res.write(`data: ${JSON.stringify(filteredEvent)}\n\n`);
    } catch {
      sseClients.delete(res);
    }
  }
}

function clearCreatorTimer() {
  if (creatorTimer) {
    clearTimeout(creatorTimer);
    creatorTimer = null;
  }
}

function clearReviveTimer() {
  if (reviveTimer) {
    clearTimeout(reviveTimer);
    reviveTimer = null;
  }
}

function clearTestTimer() {
  if (testTimer) {
    clearTimeout(testTimer);
    testTimer = null;
  }
  testRunAt = null;
}

function normalizeIntervalMinutes(intervalMinutes) {
  const mins = Number(intervalMinutes);
  if (!Number.isFinite(mins) || mins <= 0) {
    throw new Error("Interval scheduler harus lebih besar dari 0 menit.");
  }
  if (mins > 1440) {
    throw new Error("Interval scheduler maksimal 1440 menit.");
  }
  return Math.round(mins);
}

function scheduleNextCreatorRun(delayMs = creatorIntervalMinutes * 60 * 1000) {
  clearCreatorTimer();
  if (!creatorEnabled) {
    creatorNextRunAt = null;
    return;
  }

  creatorNextRunAt = new Date(Date.now() + delayMs).toISOString();
  creatorTimer = setTimeout(async () => {
    creatorTimer = null;
    creatorNextRunAt = null;
    broadcastLog({ type: "info", msg: "⏰ Auto-Scheduler Creator trigger: membuat akun baru..." });
    await triggerAutoToken(false, { source: "scheduler", mode: "create_only" });
    if (creatorEnabled) {
      scheduleNextCreatorRun();
    }
  }, delayMs);
}

function scheduleNextReviveRun(delayMs = reviveIntervalMinutes * 60 * 1000) {
  clearReviveTimer();
  if (!reviveEnabled) {
    reviveNextRunAt = null;
    return;
  }

  reviveNextRunAt = new Date(Date.now() + delayMs).toISOString();
  reviveTimer = setTimeout(async () => {
    reviveTimer = null;
    reviveNextRunAt = null;
    broadcastLog({ type: "info", msg: "⏰ Auto-Scheduler Revive trigger: memulihkan akun expired..." });
    await triggerAutoToken(false, { source: "scheduler", mode: "revive_only" });
    if (reviveEnabled) {
      scheduleNextReviveRun();
    }
  }, delayMs);
}

/** 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();

  if (accounts.length === 0) {
    broadcastLog({ type: "info", msg: "ℹ️ Pool kosong, tidak ada akun untuk di-revive." });
    return 0;
  }

  broadcastLog({ type: "info", msg: `🔍 Memeriksa ${accounts.length} akun di pool untuk revive...` });

  const toRevive = [];
  for (const a of accounts) {
    const isExp = Accounts.isExpired(a.token) || a.expired;
    const isArchived = Boolean(a.archived);
    const hasCredentials = a.email && a.password;
    const runsOk = (a.runs || 0) < Accounts.MONTHLY_RUN_LIMIT;

    if (isArchived) {
      broadcastLog({ type: "info", msg: `  📦 ${a.label || a.email}: ada di archive bulan ${a.archivedMonth || "-" }, skip revive` });
      continue;
    }
    if (!isExp) {
      broadcastLog({ type: "info", msg: `  ✅ ${a.label || a.email}: masih aktif, skip revive` });
      continue;
    }
    if (!hasCredentials) {
      broadcastLog({ type: "warn", msg: `  ⚠️ ${a.label || a.id}: expired tapi tidak punya email/password, tidak bisa revive` });
      continue;
    }
    if (!runsOk) {
      broadcastLog({ type: "warn", msg: `  ⚠️ ${a.email}: expired, runs=${a.runs} (>=${Accounts.MONTHLY_RUN_LIMIT}), skip` });
      continue;
    }

    broadcastLog({ type: "info", msg: `  🔄 ${a.email}: expired, runs=${a.runs || 0}, siap untuk revive!` });
    toRevive.push(a);
  }

  if (toRevive.length === 0) {
    broadcastLog({ type: "info", msg: "ℹ️ Tidak ada akun yang memenuhi syarat untuk revive." });
    return 0;
  }

  broadcastLog({ type: "info", msg: `🔄 Mencoba revive ${toRevive.length} akun expired...` });

  let revivedCount = 0;
  for (const acc of toRevive) {
    try {
      broadcastLog({ type: "info", msg: `🔄 Revive akun: ${acc.email}...` });
      const result = await refreshExistingAccountToken(acc.id, acc.email, acc.password, (event) => broadcastLog(event));
      if (result.ok) {
        revivedCount++;
        broadcastLog({ type: "info", msg: `✅ Revive berhasil: ${acc.email}` });
      } else {
        broadcastLog({ type: "warn", msg: `⚠️ Revive gagal: ${acc.email} — ${result.error}` });
      }
    } catch (err) {
      broadcastLog({ type: "warn", 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, { source = "manual", mode = "all" } = {}) {
  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 (${source}, mode: ${mode})...` });

  try {
    let revived = 0;
    
    // Run revive if mode is all or revive_only
    if (mode === "all" || mode === "revive_only") {
      revived = await reviveExpiredAccounts();
    }

    // Stop here if revive_only
    if (mode === "revive_only") {
      isRunning = false;
      consecutiveFailures = 0;
      lastRunResult = {
        ok: true,
        msg: revived > 0
          ? `Revive selesai. ${revived} akun berhasil dihidupkan kembali.`
          : "Revive selesai. Tidak ada akun yang memenuhi syarat revive.",
      };
      broadcastLog({ type: "success", msg: `✅ ${lastRunResult.msg}` });
      return lastRunResult;
    }

    // If mode is all, check if we need to stop before creating new accounts
    if (mode === "all") {
      if (!force && !poolNeedsRefresh()) {
        broadcastLog({ type: "info", msg: "ℹ️ Pool sekarang memiliki akun aktif, selesai." });
        isRunning = false;
        consecutiveFailures = 0;
        lastRunResult = {
          ok: true,
          msg: revived > 0
            ? `Berhasil revive ${revived} akun dan pool kembali aktif.`
            : "Pool aktif, tidak perlu tindakan tambahan.",
        };
        broadcastLog({ type: "success", msg: `✅ ${lastRunResult.msg}` });
        return lastRunResult;
      }

      if (process.env.AUTO_REVIVE_ONLY === "true") {
        broadcastLog({ type: "info", msg: "ℹ️ Mode Hanya Revive (AUTO_REVIVE_ONLY) aktif. Tidak membuat akun baru." });
        isRunning = false;
        consecutiveFailures = 0;
        lastRunResult = {
          ok: true,
          msg: revived > 0
            ? `Mode Hanya Revive selesai. ${revived} akun berhasil dihidupkan kembali.`
            : "Mode Hanya Revive selesai. Tidak ada akun yang bisa di-revive.",
        };
        broadcastLog({ type: "success", msg: `✅ ${lastRunResult.msg}` });
        return lastRunResult;
      }
    }

    broadcastLog({ type: "info", msg: "⏳ Menjalankan pembuatan akun baru..." });
    const result = await runFullFlow((event) => broadcastLog(event));
    lastRunResult = result;
    isRunning = false;

    if (result.ok) {
      consecutiveFailures = 0;
      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 Creator dihentikan otomatis karena gagal 3 kali berturut-turut." });
        stopCreatorScheduler();
      }
    }
    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 Creator dihentikan otomatis karena gagal 3 kali berturut-turut." });
      stopCreatorScheduler();
    }
    return lastRunResult;
  }
}

export function startCreatorScheduler(intervalMinutes = 45) {
  creatorIntervalMinutes = normalizeIntervalMinutes(intervalMinutes);
  creatorEnabled = true;
  scheduleNextCreatorRun();
  broadcastLog({ type: "info", msg: `⏰ Scheduler Pembuat Akun dimulai: setiap ${creatorIntervalMinutes} menit` });
  return creatorIntervalMinutes;
}

export function stopCreatorScheduler() {
  const wasActive = creatorEnabled || creatorTimer !== null;
  creatorEnabled = false;
  clearCreatorTimer();
  creatorNextRunAt = null;
  if (wasActive) {
    broadcastLog({ type: "info", msg: "⏹️ Scheduler Pembuat Akun dihentikan." });
  }
}

export function startReviveScheduler(intervalMinutes = 15) {
  reviveIntervalMinutes = normalizeIntervalMinutes(intervalMinutes);
  reviveEnabled = true;
  scheduleNextReviveRun();
  broadcastLog({ type: "info", msg: `⏰ Scheduler Pemulih Akun dimulai: setiap ${reviveIntervalMinutes} menit` });
  return reviveIntervalMinutes;
}

export function stopReviveScheduler() {
  const wasActive = reviveEnabled || reviveTimer !== null;
  reviveEnabled = false;
  clearReviveTimer();
  reviveNextRunAt = null;
  if (wasActive) {
    broadcastLog({ type: "info", msg: "⏹️ Scheduler Pemulih Akun dihentikan." });
  }
}

export function scheduleTestRun(delaySeconds = 15) {
  const secs = Number(delaySeconds);
  if (!Number.isFinite(secs) || secs < 5 || secs > 300) {
    throw new Error("Delay test scheduler harus antara 5 sampai 300 detik.");
  }

  clearTestTimer();
  testRunAt = new Date(Date.now() + secs * 1000).toISOString();
  broadcastLog({ type: "info", msg: `🧪 Test scheduler dijadwalkan ${secs} detik dari sekarang.` });

  testTimer = setTimeout(async () => {
    testTimer = null;
    testRunAt = null;
    broadcastLog({ type: "info", msg: "🧪 Test scheduler trigger: memeriksa pool..." });
    await triggerAutoToken(false, { source: "test" });
  }, secs * 1000);

  return { delaySeconds: secs, runAt: testRunAt };
}

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,
    creatorActive: creatorEnabled,
    creatorIntervalMinutes: creatorIntervalMinutes,
    creatorNextRunAt,
    reviveActive: reviveEnabled,
    reviveIntervalMinutes: reviveIntervalMinutes,
    reviveNextRunAt,
    lastRunAt,
    lastRunResult,
    poolNeedsRefresh: poolNeedsRefresh(),
    headless: process.env.PLAYWRIGHT_HEADLESS !== "false",
    testRunAt,
  };
}
