import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
import { createServer } from "node:http";
import { loadConfig } from "file:///D:/Codex/FilyX/apps/bot-engine/src/config.ts";
import { KickOAuthClient } from "file:///D:/Codex/FilyX/apps/bot-engine/src/kick/KickOAuthClient.ts";
import { SessionVault } from "file:///D:/Codex/FilyX/apps/bot-engine/src/session/SessionVault.ts";

const base64Url = (value: Buffer): string => value.toString("base64url");
const safeEqual = (left: string, right: string): boolean => {
  const a = Buffer.from(left);
  const b = Buffer.from(right);
  return a.length === b.length && timingSafeEqual(a, b);
};

const config = loadConfig();
config.kickScopes = [...new Set([...config.kickScopes, "events:subscribe"])];
const redirect = new URL(config.kickRedirectUri);
if (redirect.protocol !== "http:" || !["localhost", "127.0.0.1"].includes(redirect.hostname) || !redirect.port) {
  throw new Error("Adresse de redirection OAuth locale invalide.");
}

const state = base64Url(randomBytes(32));
const verifier = base64Url(randomBytes(64));
const challenge = base64Url(createHash("sha256").update(verifier).digest());
const authorization = new URL("https://id.kick.com/oauth/authorize");
authorization.search = new URLSearchParams({
  response_type: "code",
  client_id: config.kickClientId,
  redirect_uri: config.kickRedirectUri,
  scope: config.kickScopes.join(" "),
  code_challenge: challenge,
  code_challenge_method: "S256",
  state,
}).toString();

const callback = new Promise<string>((resolve, reject) => {
  let timeout: NodeJS.Timeout | undefined;
  const server = createServer((request, response) => {
    const requestUrl = new URL(request.url ?? "/", config.kickRedirectUri);
    if (requestUrl.pathname !== redirect.pathname) {
      response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
      response.end("Page introuvable.");
      return;
    }
    const returnedState = requestUrl.searchParams.get("state") ?? "";
    const code = requestUrl.searchParams.get("code") ?? "";
    const oauthError = requestUrl.searchParams.get("error") ?? "";
    const validState = safeEqual(returnedState, state);
    const success = validState && Boolean(code) && !oauthError;
    response.writeHead(success ? 200 : 400, {
      "Content-Type": "text/html; charset=utf-8",
      "Cache-Control": "no-store",
      "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'",
    });
    response.end(
      `<!doctype html><html lang="fr"><meta charset="utf-8"><title>FilyX OAuth</title>`
      + `<body style="font:18px system-ui;padding:40px;background:#151515;color:#fff">`
      + `<h1>${success ? "FilyX est autorisé" : "Autorisation refusée"}</h1>`
      + `<p>${success ? "Vous pouvez revenir dans Codex." : "Revenez dans Codex pour voir le détail."}</p>`
      + `</body></html>`,
    );
    server.close();
    if (timeout) clearTimeout(timeout);
    if (!validState) reject(new Error("État OAuth invalide."));
    else if (oauthError) reject(new Error(`Kick a refusé l'autorisation : ${oauthError}`));
    else if (!code) reject(new Error("Code OAuth Kick absent."));
    else resolve(code);
  });
  server.on("error", reject);
  const host = redirect.hostname === "localhost" ? "127.0.0.1" : redirect.hostname;
  server.listen(Number(redirect.port), host, () => {
    process.stdout.write(`AUTH_URL=${authorization.toString()}\n`);
  });
  timeout = setTimeout(() => {
    server.close();
    reject(new Error("Autorisation Kick expirée après 10 minutes."));
  }, 10 * 60_000);
});

const code = await callback;
const vault = new SessionVault(config.vaultPath, config.oauthMasterKey);
const client = new KickOAuthClient(config, vault);
const session = await client.exchangeAuthorizationCode(code, verifier);
process.stdout.write(`OAUTH_OK account=${session.accountUsername} events_subscribe=${session.scopes.includes("events:subscribe")}\n`);
