/* =====================================================================
   lib/oauth-handlers.js — gemeinsame Start-/Callback-Logik für alle OAuth-Anbieter. 1:1 portiert
   aus functions/_shared/oauth-handlers.js, auf Express (req/res) statt Cloudflare
   Request/Response umgestellt.
   ===================================================================== */

import {
  erzeugeZufallswert,
  codeChallengeFuer,
  baueAutorisierungsUrl,
  istProviderKonfiguriert,
  tauscheCodeGegenToken,
  holeNutzerprofil,
} from "./oauth.js";
import { signCustomerSession, setCustomerCookie, CUSTOMER_SESSION_TAGE } from "./customer-auth.js";
import { db } from "../db.js";

const STATE_COOKIE = "vandiy_oauth_state";
const VERIFIER_COOKIE = "vandiy_oauth_verifier";
const LANG_COOKIE = "vandiy_oauth_lang";
const OAUTH_TEMP_MAXAGE = 600; // Sekunden
const ERLAUBTE_SPRACHEN = ["", "en", "ch", "fr"];

function langPrefix(lang) {
  return ERLAUBTE_SPRACHEN.includes(lang) ? lang : "";
}

function originVon(req) {
  return `${req.protocol}://${req.get("host")}`;
}

/** GET /api/auth/:provider/start */
export async function starteOAuth(req, res, providerName) {
  const origin = originVon(req);
  const lang = langPrefix(req.query.lang || "");

  if (!istProviderKonfiguriert(providerName)) {
    return res.redirect(302, `${origin}/${lang ? lang + "/" : ""}konto/?login_error=${providerName}_unconfigured`);
  }

  const state = erzeugeZufallswert(24);
  const codeVerifier = erzeugeZufallswert(48);
  const codeChallenge = await codeChallengeFuer(codeVerifier);
  const redirectUri = `${origin}/api/auth/${providerName}/callback`;
  const authUrl = baueAutorisierungsUrl(providerName, { redirectUri, state, codeChallenge });

  const cookiePath = `/api/auth/${providerName}`;
  const cookieOpts = { path: cookiePath, maxAge: OAUTH_TEMP_MAXAGE * 1000, httpOnly: true, secure: true, sameSite: "lax" };
  res.cookie(STATE_COOKIE, state, cookieOpts);
  res.cookie(VERIFIER_COOKIE, codeVerifier, cookieOpts);
  res.cookie(LANG_COOKIE, lang, cookieOpts);
  return res.redirect(302, authUrl);
}

/** GET /api/auth/:provider/callback */
export async function verarbeiteOAuthCallback(req, res, providerName) {
  const origin = originVon(req);
  const code = req.query.code;
  const state = req.query.state;
  const errorParam = req.query.error;
  const lang = langPrefix(req.cookies?.[LANG_COOKIE] || "");
  const kontoPfad = `${origin}/${lang ? lang + "/" : ""}konto/`;
  const cookiePath = `/api/auth/${providerName}`;

  function loescheTempCookies() {
    res.clearCookie(STATE_COOKIE, { path: cookiePath });
    res.clearCookie(VERIFIER_COOKIE, { path: cookiePath });
    res.clearCookie(LANG_COOKIE, { path: cookiePath });
  }
  function fehlerRedirect(grund) {
    loescheTempCookies();
    return res.redirect(302, `${kontoPfad}?login_error=${grund}`);
  }

  if (errorParam) return fehlerRedirect(`${providerName}_denied`);
  if (!code || !state) return fehlerRedirect(`${providerName}_invalid`);

  const stateCookie = req.cookies?.[STATE_COOKIE];
  const verifierCookie = req.cookies?.[VERIFIER_COOKIE];
  if (!stateCookie || stateCookie !== state || !verifierCookie) {
    return fehlerRedirect(`${providerName}_state_mismatch`);
  }

  if (!process.env.CUSTOMER_SESSION_SECRET) {
    return fehlerRedirect(`${providerName}_backend_unconfigured`);
  }

  try {
    const redirectUri = `${origin}/api/auth/${providerName}/callback`;
    const accessToken = await tauscheCodeGegenToken(providerName, { code, redirectUri, codeVerifier: verifierCookie });
    const profil = await holeNutzerprofil(providerName, accessToken);

    const now = new Date().toISOString();
    const bestehend = db
      .prepare(`SELECT id FROM customers WHERE provider = ? AND provider_user_id = ?`)
      .get(providerName, profil.providerUserId);

    let customerId;
    if (bestehend) {
      customerId = bestehend.id;
      db.prepare(`UPDATE customers SET email = ?, name = ?, updated_at = ?, last_login_at = ? WHERE id = ?`)
        .run(profil.email, profil.name, now, now, customerId);
    } else {
      const insert = db
        .prepare(
          `INSERT INTO customers (created_at, updated_at, last_login_at, provider, provider_user_id, email, name) VALUES (?,?,?,?,?,?,?)`
        )
        .run(now, now, now, providerName, profil.providerUserId, profil.email, profil.name);
      customerId = insert.lastInsertRowid;
    }

    const sessionToken = await signCustomerSession(customerId, process.env.CUSTOMER_SESSION_SECRET);
    setCustomerCookie(res, sessionToken, CUSTOMER_SESSION_TAGE * 24 * 60 * 60);
    loescheTempCookies();
    return res.redirect(302, `${origin}/${lang ? lang + "/" : ""}konto/angemeldet/`);
  } catch (err) {
    return fehlerRedirect(`${providerName}_failed`);
  }
}
