import { $inject, z } from "alepha";
import { $route, type ServerReply } from "alepha/server";
import { MemoryPaymentProvider } from "../providers/MemoryPaymentProvider.ts";
import { PaymentProvider } from "../providers/PaymentProvider.ts";
import { PaymentService } from "../services/PaymentService.ts";

const FORBIDDEN_HTML =
  "<!doctype html><meta charset=utf-8><title>Mock checkout</title>" +
  "<p>Mock checkout is only available with the in-memory payment provider.</p>";

const escapeHtml = (s: string) =>
  s.replace(/[&<>"']/g, (c) =>
    c === "&"
      ? "&amp;"
      : c === "<"
        ? "&lt;"
        : c === ">"
          ? "&gt;"
          : c === '"'
            ? "&quot;"
            : "&#39;",
  );

const formatAmount = (cents: number, currency: string) => {
  const value = (cents / 100).toFixed(2);
  return `${value} ${currency.toUpperCase()}`;
};

const renderPage = (opts: {
  intentId: string;
  amount: string;
  returnUrl: string;
}) => `<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Checkout</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    :root { color-scheme: light; }
    * { box-sizing: border-box; }
    body {
      display:flex; min-height:100vh; align-items:center; justify-content:center;
      margin:0; padding:1rem; background:#f8fafc; color:#0b1120;
      font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
    }
    .card {
      background:#fff; border:1px solid #e2e8f0; border-radius:16px;
      box-shadow:0 12px 40px rgba(11,17,32,.08); max-width:400px; width:100%;
      overflow:hidden;
    }
    .head { padding:1.5rem 1.75rem 1.25rem; border-bottom:1px solid #e2e8f0; }
    .badge {
      display:inline-flex; align-items:center; gap:.35rem;
      background:#fff7ed; color:#c2410c; border:1px solid #fed7aa;
      font-size:.7rem; font-weight:600; letter-spacing:.04em;
      padding:3px 10px; border-radius:999px; text-transform:uppercase;
    }
    .label { margin:.9rem 0 0; font-size:.8rem; color:#64748b; }
    .amount { font-size:2.25rem; font-weight:800; letter-spacing:-.02em; margin:.15rem 0 0; }
    .body { padding:1.5rem 1.75rem 1.75rem; }
    .field { margin-bottom: .9rem; }
    .field label { display:block; font-size:.75rem; font-weight:600; color:#334155; margin-bottom:.3rem; }
    .field input {
      width:100%; padding:.65rem .8rem; border:1px solid #e2e8f0; border-radius:10px;
      font-size:.9rem; background:#f8fafc; color:#475569; font-family:inherit;
    }
    .grid { display:grid; grid-template-columns:1fr 1fr; gap:.75rem; }
    .pay {
      width:100%; padding:.85rem 1rem; border-radius:999px; border:0; cursor:pointer;
      background:#f97316; color:#fff; font-size:1rem; font-weight:700; font-family:inherit;
      box-shadow:0 6px 20px rgba(249,115,22,.35); transition:transform .15s, box-shadow .15s;
    }
    .pay:hover { transform:translateY(-1px); box-shadow:0 10px 26px rgba(249,115,22,.45); }
    .cancel {
      width:100%; margin-top:.6rem; padding:.7rem 1rem; border-radius:999px; cursor:pointer;
      background:transparent; border:0; color:#64748b; font-size:.85rem; font-family:inherit;
    }
    .cancel:hover { color:#0b1120; }
    .secure {
      display:flex; align-items:center; justify-content:center; gap:.35rem;
      font-size:.72rem; color:#94a3b8; margin-top:1rem;
    }
    .meta { font-size:.68rem; color:#cbd5e1; margin-top:.75rem; word-break:break-all; text-align:center; }
  </style>
</head>
<body>
  <div class="card">
    <div class="head">
      <span class="badge">Mode test — paiement simulé</span>
      <p class="label">Montant à payer</p>
      <p class="amount">${escapeHtml(opts.amount)}</p>
    </div>
    <div class="body">
      <div class="field">
        <label for="cc-num">Numéro de carte</label>
        <input id="cc-num" value="4242 4242 4242 4242" readonly />
      </div>
      <div class="grid">
        <div class="field">
          <label for="cc-exp">Expiration</label>
          <input id="cc-exp" value="12 / 34" readonly />
        </div>
        <div class="field">
          <label for="cc-cvc">CVC</label>
          <input id="cc-cvc" value="123" readonly />
        </div>
      </div>
      <form method="post" action="/payments/mock-checkout/${opts.intentId}/confirm">
        <input type="hidden" name="returnUrl" value="${escapeHtml(opts.returnUrl)}" />
        <button type="submit" class="pay">Payer ${escapeHtml(opts.amount)}</button>
      </form>
      <form method="post" action="/payments/mock-checkout/${opts.intentId}/cancel">
        <input type="hidden" name="returnUrl" value="${escapeHtml(opts.returnUrl)}" />
        <button type="submit" class="cancel">Annuler et revenir au site</button>
      </form>
      <p class="secure">&#128274; Aucune carte n'est débitée — environnement de développement</p>
      <p class="meta">intent: ${opts.intentId}</p>
    </div>
  </div>
</body>
</html>`;

const appendStatusParam = (returnUrl: string, status: "success" | "cancel") => {
  try {
    const url = new URL(returnUrl, "http://placeholder.local");
    url.searchParams.set("booking", status);
    return returnUrl.startsWith("http")
      ? url.toString()
      : url.pathname + url.search + url.hash;
  } catch {
    return returnUrl;
  }
};

export class MockCheckoutController {
  protected readonly url = "/payments/mock-checkout";
  protected readonly payments = $inject(PaymentService);
  protected readonly provider = $inject(PaymentProvider);

  protected isMemoryProvider() {
    return this.provider instanceof MemoryPaymentProvider;
  }

  protected forbidden(reply: ServerReply) {
    reply.headers["content-type"] = "text/html; charset=utf-8";
    reply.status = 403;
    return FORBIDDEN_HTML;
  }

  public readonly mockCheckoutPage = $route({
    method: "GET",
    path: `${this.url}/:id`,
    schema: {
      params: z.object({ id: z.uuid() }),
      query: z.object({ returnUrl: z.text({ size: "rich" }).optional() }),
    },
    handler: async ({ params, query, reply }) => {
      if (!this.isMemoryProvider()) return this.forbidden(reply);
      const intent = await this.payments.getIntent(params.id);
      reply.headers["content-type"] = "text/html; charset=utf-8";
      return renderPage({
        intentId: intent.id,
        amount: formatAmount(intent.amount, intent.currency),
        returnUrl: query.returnUrl ?? "/",
      });
    },
  });

  public readonly mockCheckoutConfirm = $route({
    method: "POST",
    path: `${this.url}/:id/confirm`,
    schema: {
      params: z.object({ id: z.uuid() }),
      body: z.object({ returnUrl: z.text({ size: "rich" }).optional() }),
    },
    handler: async ({ params, body, reply }) => {
      if (!this.isMemoryProvider()) return this.forbidden(reply);
      await this.payments.handleWebhookEvent(params.id, "captured");
      reply.redirect(appendStatusParam(body.returnUrl ?? "/", "success"), 302);
    },
  });

  public readonly mockCheckoutCancel = $route({
    method: "POST",
    path: `${this.url}/:id/cancel`,
    schema: {
      params: z.object({ id: z.uuid() }),
      body: z.object({ returnUrl: z.text({ size: "rich" }).optional() }),
    },
    handler: async ({ params, body, reply }) => {
      if (!this.isMemoryProvider()) return this.forbidden(reply);
      await this.payments.handleWebhookEvent(params.id, "failed");
      reply.redirect(appendStatusParam(body.returnUrl ?? "/", "cancel"), 302);
    },
  });
}
