// cli/commands/invite.js
// clauth invite generate [--uses <n>] [--expires <hours>]
// clauth invite list
// clauth invite revoke <code>
//
// Admin generates invite codes. Friends redeem them via `clauth join`.

import chalk from "chalk";
import ora from "ora";
import crypto from "crypto";
import Conf from "conf";
import { getConfOptions } from "../conf-path.js";
import * as api from "../api.js";
import { getMachineHash, deriveToken } from "../fingerprint.js";

// ============================================================
// Generate a human-friendly invite code: XXXX-XXXX-XXXX
// No ambiguous characters (0/O, 1/I)
// ============================================================
function generateCode() {
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
  const segments = [];
  for (let s = 0; s < 3; s++) {
    let seg = "";
    for (let i = 0; i < 4; i++) {
      seg += chars[crypto.randomInt(chars.length)];
    }
    segments.push(seg);
  }
  return segments.join("-");
}

// ============================================================
// Main invite handler
// ============================================================
export async function runInvite(action, opts) {
  const config = new Conf(getConfOptions());

  if (action === "generate") {
    // Requires admin auth — prompt for password
    const inquirer = (await import("inquirer")).default;
    const { pw } = await inquirer.prompt([{
      type: "password",
      name: "pw",
      message: "Admin password:",
      mask: "*",
      validate: v => v.length >= 8 || "Password must be at least 8 characters",
    }]);

    const machineHash = getMachineHash();
    const { token, timestamp } = deriveToken(pw, machineHash);

    const code = generateCode();
    const maxUses = parseInt(opts.uses, 10) || 1;
    const expiresHours = parseInt(opts.expires, 10) || 168; // 7 days default
    const expiresAt = new Date(Date.now() + expiresHours * 3600000).toISOString();

    const spinner = ora("Creating invite...").start();

    // Try to store invite in Supabase via Edge Function
    let storedRemote = false;
    try {
      const supabaseUrl = config.get("supabase_url");
      const anonKey = config.get("supabase_anon_key");

      if (supabaseUrl && anonKey) {
        const res = await fetch(`${supabaseUrl}/functions/v1/auth-vault/create-invite`, {
          method: "POST",
          headers: {
            "Authorization": `Bearer ${anonKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            machine_hash: machineHash,
            token,
            timestamp,
            password: pw,
            invite_code: code,
            max_uses: maxUses,
            expires_hours: expiresHours,
          }),
        });

        if (res.ok) {
          const body = await res.json();
          if (body.success) storedRemote = true;
        }
      }
    } catch {
      // Edge Function may not support invites yet — fall through to local
    }

    // Always store locally as well (source of truth for `invite list`)
    const invites = config.get("invites") || [];
    invites.push({
      code,
      max_uses: maxUses,
      uses: 0,
      expires_at: expiresAt,
      created_at: new Date().toISOString(),
      stored_remote: storedRemote,
    });
    config.set("invites", invites);

    spinner.succeed(storedRemote ? "Invite created (synced to vault)" : "Invite created (local only)");

    console.log(chalk.green(`\n  Invite code: ${chalk.bold(code)}`));
    console.log(chalk.gray(`  Max uses:    ${maxUses}`));
    console.log(chalk.gray(`  Expires:     ${expiresHours}h (${expiresAt})`));
    console.log("");
    console.log(chalk.cyan("  Share this with your friend:"));
    console.log(chalk.white(`  npm install -g @lifeaitools/clauth && clauth join ${code}`));
    console.log("");

  } else if (action === "list") {
    const invites = config.get("invites") || [];
    if (invites.length === 0) {
      console.log(chalk.gray("\n  No invites generated.\n"));
      return;
    }

    console.log(chalk.cyan("\n  Invites:\n"));
    console.log(
      chalk.bold(
        "  " +
        "CODE".padEnd(16) +
        "STATUS".padEnd(12) +
        "USES".padEnd(10) +
        "EXPIRES"
      )
    );
    console.log("  " + "-".repeat(60));

    for (const inv of invites) {
      const now = new Date();
      const expired = new Date(inv.expires_at) < now;
      const exhausted = inv.uses >= inv.max_uses;
      const status = expired
        ? chalk.red("expired")
        : exhausted
          ? chalk.yellow("used up")
          : chalk.green("active");

      const uses = `${inv.uses}/${inv.max_uses}`;
      const expStr = new Date(inv.expires_at).toLocaleDateString();

      console.log(
        `  ${inv.code.padEnd(16)}${status.padEnd(12 + (status.length - (expired ? 7 : exhausted ? 7 : 6)))}  ${uses.padEnd(10)}${expStr}`
      );
    }
    console.log("");

  } else if (action === "revoke") {
    const code = opts.code;
    if (!code) {
      console.log(chalk.red("\n  Usage: clauth invite revoke <code>\n"));
      return;
    }

    const invites = config.get("invites") || [];
    const idx = invites.findIndex(i => i.code === code.toUpperCase());
    if (idx === -1) {
      console.log(chalk.red(`\n  Invite ${code} not found.\n`));
      return;
    }

    invites.splice(idx, 1);
    config.set("invites", invites);
    console.log(chalk.green(`\n  Invite ${code} revoked.\n`));

  } else {
    console.log(chalk.yellow(`\n  Unknown invite action: ${action}`));
    console.log(chalk.gray("  Usage: clauth invite generate | list | revoke <code>\n"));
  }
}
