// Authentication module for z-image.ai
// Stores and manages the Better Auth session cookie

import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { createServer } from "node:http";
import { exec } from "node:child_process";

const CONFIG_DIR = join(homedir(), ".config", "zimage-mcp");
const AUTH_FILE = join(CONFIG_DIR, "auth.json");

interface AuthConfig {
  sessionToken: string;
  updatedAt: string;
}

function ensureConfigDir(): void {
  if (!existsSync(CONFIG_DIR)) {
    mkdirSync(CONFIG_DIR, { recursive: true });
  }
}

export function getSessionToken(): string | null {
  try {
    if (!existsSync(AUTH_FILE)) return null;
    const config: AuthConfig = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
    return config.sessionToken || null;
  } catch {
    return null;
  }
}

export function saveSessionToken(token: string): void {
  ensureConfigDir();
  const config: AuthConfig = {
    sessionToken: token,
    updatedAt: new Date().toISOString(),
  };
  writeFileSync(AUTH_FILE, JSON.stringify(config, null, 2), "utf-8");
}

// Extract session token from a raw cookie string
function extractToken(cookieStr: string): string | null {
  // Try better-auth.session_token first
  const match = cookieStr.match(/better-auth\.session_token=([^;\s]+)/);
  if (match) return match[1];
  // If the string looks like a bare token (no = sign), use it directly
  if (!cookieStr.includes("=") && cookieStr.length > 20) return cookieStr.trim();
  return null;
}

// Open URL in the user's default browser
function openBrowser(url: string): void {
  const cmd =
    process.platform === "darwin"
      ? `open "${url}"`
      : process.platform === "win32"
        ? `start "${url}"`
        : `xdg-open "${url}"`;
  exec(cmd, () => {});
}

/**
 * Streamlined interactive auth flow:
 * 1. Starts a tiny local HTTP server
 * 2. Opens z-image.ai — user logs in with Google
 * 3. User clicks a bookmarklet or pastes a one-liner in console
 * 4. Local server captures the cookie and saves it
 *
 * Called via: zimage-mcp auth
 */
export async function interactiveAuth(): Promise<string> {
  return new Promise((resolve, reject) => {
    const port = 39271;

    const html = `<!DOCTYPE html>
<html><head><title>Z-Image MCP Auth</title>
<style>
  body { font-family: system-ui, sans-serif; max-width: 600px; margin: 60px auto; padding: 0 20px; background: #0a0a0a; color: #e0e0e0; }
  h1 { color: #fff; }
  .step { background: #1a1a2e; border-radius: 8px; padding: 16px 20px; margin: 16px 0; border-left: 3px solid #6c63ff; }
  .step-num { color: #6c63ff; font-weight: bold; font-size: 1.1em; }
  code { background: #2a2a3e; padding: 2px 6px; border-radius: 4px; font-size: 0.95em; }
  button { background: #6c63ff; color: white; border: none; padding: 12px 24px; border-radius: 6px; font-size: 1em; cursor: pointer; margin: 8px 4px; }
  button:hover { background: #5a52e0; }
  .success { background: #1a3a1a; border-left-color: #4caf50; display: none; }
  pre { background: #1a1a2e; padding: 12px; border-radius: 6px; overflow-x: auto; font-size: 0.85em; user-select: all; }
  a { color: #6c63ff; }
</style></head>
<body>
  <h1>🔐 Z-Image MCP Authentication</h1>

  <div class="step">
    <span class="step-num">Step 1</span> — Open z-image.ai and log in with Google<br><br>
    <button onclick="window.open('https://z-image.ai','_blank')">Open z-image.ai →</button>
  </div>

  <div class="step">
    <span class="step-num">Step 2</span> — After logging in, click this button to grab your session automatically:<br><br>
    <button onclick="grabCookie()">✨ I'm logged in — Grab Session</button>
    <p style="margin-top:12px;font-size:0.85em;color:#999;">
      If the button doesn't work, open the browser console on z-image.ai (F12 → Console) and paste:
    </p>
    <pre>fetch('http://localhost:${port}/capture',{method:'POST',headers:{'Content-Type':'text/plain'},body:document.cookie})</pre>
  </div>

  <div class="step success" id="success">
    <span class="step-num">✅ Done!</span> — Session captured and saved.<br>
    You can close this tab. The MCP server is ready to use.
  </div>

  <script>
  async function grabCookie() {
    // Try opening z-image.ai in a hidden iframe to get cookies (same-site won't work, but try)
    // Fallback: ask user to paste
    try {
      const resp = await fetch('https://z-image.ai/api/user/get-user-info', { credentials: 'include' });
      if (resp.ok) {
        // We're on same origin? unlikely but handle it
      }
    } catch(e) {}

    // Prompt user to paste cookie
    const cookie = prompt('Paste your cookie from z-image.ai browser console:\\n\\nIn z-image.ai tab, press F12 → Console → type: document.cookie → Enter → copy the result');
    if (cookie) {
      const resp = await fetch('http://localhost:${port}/capture', {
        method: 'POST',
        headers: { 'Content-Type': 'text/plain' },
        body: cookie
      });
      if (resp.ok) {
        document.getElementById('success').style.display = 'block';
      }
    }
  }
  </script>
</body></html>`;

    const server = createServer((req, res) => {
      // CORS headers for cross-origin POST from z-image.ai console
      res.setHeader("Access-Control-Allow-Origin", "*");
      res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
      res.setHeader("Access-Control-Allow-Headers", "Content-Type");

      if (req.method === "OPTIONS") {
        res.writeHead(204);
        res.end();
        return;
      }

      if (req.url === "/capture" && req.method === "POST") {
        let body = "";
        req.on("data", (chunk: Buffer) => (body += chunk.toString()));
        req.on("end", () => {
          const token = extractToken(body);
          if (token) {
            saveSessionToken(token);
            res.writeHead(200, { "Content-Type": "text/plain" });
            res.end("OK — session saved");
            // Give time for response to send, then resolve
            setTimeout(() => {
              server.close();
              resolve(token);
            }, 500);
          } else {
            res.writeHead(400, { "Content-Type": "text/plain" });
            res.end("Could not extract session token from cookie string");
          }
        });
        return;
      }

      // Serve auth page
      res.writeHead(200, { "Content-Type": "text/html" });
      res.end(html);
    });

    server.listen(port, () => {
      const url = `http://localhost:${port}`;
      console.error(`\n🔐 Z-Image MCP Authentication`);
      console.error(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
      console.error(`Opening auth page: ${url}\n`);
      console.error(`Steps:`);
      console.error(`  1. Log in to z-image.ai with Google`);
      console.error(`  2. Open z-image.ai console (F12 → Console)`);
      console.error(`  3. Run: document.cookie`);
      console.error(`  4. Copy the result and paste it in the auth page\n`);
      openBrowser(url);
    });

    server.on("error", (err: Error) => {
      reject(new Error(`Auth server failed: ${err.message}`));
    });

    // Timeout after 5 minutes
    setTimeout(() => {
      server.close();
      reject(new Error("Auth timeout — no cookie received in 5 minutes"));
    }, 5 * 60 * 1000);
  });
}

/**
 * Direct token auth — for CLI: zimage-mcp auth --token <value>
 * Or for setting from environment variable ZIMAGE_SESSION_TOKEN
 */
export function directAuth(token: string): void {
  const extracted = extractToken(token) || token.trim();
  saveSessionToken(extracted);
}

/**
 * Get the session token from config or environment, with validation
 */
export function requireAuth(): string {
  // Environment variable takes precedence
  const envToken = process.env.ZIMAGE_SESSION_TOKEN;
  if (envToken) return envToken;

  const token = getSessionToken();
  if (!token) {
    throw new Error(
      "Not authenticated. Run: zimage-mcp auth\n" +
        "Or set ZIMAGE_SESSION_TOKEN environment variable."
    );
  }
  return token;
}
