// File-based JSON store for Weavy accounts.
// Each account: { id, label, token, recipeId, addedAt, lastUsedAt, runs }

import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const STORE_PATH = path.join(__dirname, "..", "data", "accounts.json");

function ensureDir() {
  const dir = path.dirname(STORE_PATH);
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
}

function readAll() {
  ensureDir();
  if (!fs.existsSync(STORE_PATH)) return [];
  try {
    return JSON.parse(fs.readFileSync(STORE_PATH, "utf-8"));
  } catch {
    return [];
  }
}

function writeAll(list) {
  ensureDir();
  fs.writeFileSync(STORE_PATH, JSON.stringify(list, null, 2));
}

export function decodeJwt(token) {
  try {
    const [, payload] = token.split(".");
    const json = Buffer.from(payload, "base64").toString("utf-8");
    return JSON.parse(json);
  } catch {
    return null;
  }
}

export function isExpired(token) {
  const d = decodeJwt(token);
  if (!d?.exp) return false;
  return Date.now() / 1000 > d.exp;
}

export function listAccounts() {
  return readAll();
}

export function listAccountsSafe() {
  // Return without raw token (for public listing)
  return readAll().map((a) => {
    const decoded = decodeJwt(a.token);
    return {
      id: a.id,
      label: a.label,
      recipeId: a.recipeId,
      addedAt: a.addedAt,
      lastUsedAt: a.lastUsedAt,
      runs: a.runs || 0,
      email: decoded?.email,
      exp: decoded?.exp,
      expired: isExpired(a.token),
      tokenPreview: a.token.slice(0, 24) + "..." + a.token.slice(-12),
    };
  });
}

export function getAccount(id) {
  return readAll().find((a) => a.id === id) || null;
}

export function addAccount({ token, recipeId = "", label = "" }) {
  const decoded = decodeJwt(token);
  if (!decoded) throw new Error("Invalid JWT token");

  const list = readAll();
  const id = "acc_" + Math.random().toString(36).slice(2, 12);
  const acc = {
    id,
    label: label || decoded.email || decoded.name || "Akun",
    token,
    recipeId,
    addedAt: new Date().toISOString(),
    lastUsedAt: null,
    runs: 0,
  };
  list.push(acc);
  writeAll(list);
  return acc;
}

export function updateAccount(id, patch) {
  const list = readAll();
  const idx = list.findIndex((a) => a.id === id);
  if (idx < 0) throw new Error("Account not found");
  if (patch.token) {
    const decoded = decodeJwt(patch.token);
    if (!decoded) throw new Error("Invalid JWT token");
  }
  list[idx] = { ...list[idx], ...patch };
  writeAll(list);
  return list[idx];
}

export function deleteAccount(id) {
  const list = readAll();
  const idx = list.findIndex((a) => a.id === id);
  if (idx < 0) return false;
  list.splice(idx, 1);
  writeAll(list);
  return true;
}

export function markUsed(id) {
  const list = readAll();
  const idx = list.findIndex((a) => a.id === id);
  if (idx < 0) return;
  list[idx].lastUsedAt = new Date().toISOString();
  list[idx].runs = (list[idx].runs || 0) + 1;
  writeAll(list);
}

// Pick the next available (non-expired) account using least-recently-used.
// preferredId, if given, is tried first.
export function pickAccount({ preferredId } = {}) {
  const list = readAll().filter((a) => !isExpired(a.token));
  if (!list.length) return null;
  if (preferredId) {
    const p = list.find((a) => a.id === preferredId);
    if (p) return p;
  }
  // LRU: never used → first; else oldest lastUsedAt
  list.sort((a, b) => {
    if (!a.lastUsedAt && b.lastUsedAt) return -1;
    if (a.lastUsedAt && !b.lastUsedAt) return 1;
    if (!a.lastUsedAt && !b.lastUsedAt) return 0;
    return new Date(a.lastUsedAt) - new Date(b.lastUsedAt);
  });
  return list[0];
}
