import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import crypto from 'crypto';

type PaymentPrototypeBody = {
  amount?: unknown;
  currency?: unknown;
  orderId?: unknown;
  storeName?: unknown;
  market?: unknown;
  cardNumber?: unknown;
  cardHolder?: unknown;
  expiry?: unknown;
  cvc?: unknown;
  email?: unknown;
};

type ValidationResult =
  | { ok: true; value: Required<Record<keyof PaymentPrototypeBody, string>> }
  | { ok: false; errors: Record<string, string> };

export async function paymentPrototypeRoutes(app: FastifyInstance): Promise<void> {
  app.get('/payment-gateway', handlePaymentPrototypePage);
  app.get('/payment-prototype', handlePaymentPrototypePage);
  app.post('/api/prototype/payments', handlePaymentPrototypeSubmit);
}

async function handlePaymentPrototypePage(_request: FastifyRequest, reply: FastifyReply): Promise<void> {
  reply.header('content-type', 'text/html; charset=utf-8').send(renderPaymentPrototypePage());
}

async function handlePaymentPrototypeSubmit(
  request: FastifyRequest,
  reply: FastifyReply,
): Promise<void> {
  const parsed = validatePaymentPrototypeBody(request.body as PaymentPrototypeBody);

  if (!parsed.ok) {
    reply.status(400).send({ ok: false, errors: parsed.errors });
    return;
  }

  const paymentId = `demo_${crypto.randomUUID()}`;
  const cardLast4 = parsed.value.cardNumber.replace(/\D/g, '').slice(-4);

  reply.send({
    ok: true,
    paymentId,
    mode: 'local-demo-only',
    message: 'Prototype submission accepted locally. Raw card data was not stored or forwarded.',
    received: {
      orderId: parsed.value.orderId,
      amount: parsed.value.amount,
      currency: parsed.value.currency,
      market: parsed.value.market,
      email: parsed.value.email,
      card: `**** **** **** ${cardLast4}`,
    },
  });
}

function validatePaymentPrototypeBody(body: PaymentPrototypeBody | null | undefined): ValidationResult {
  const errors: Record<string, string> = {};
  const value = {
    amount: normalize(body?.amount),
    currency: normalize(body?.currency || 'PLN').toUpperCase(),
    orderId: normalize(body?.orderId),
    storeName: normalize(body?.storeName),
    market: normalize(body?.market),
    cardNumber: normalize(body?.cardNumber),
    cardHolder: normalize(body?.cardHolder),
    expiry: normalize(body?.expiry),
    cvc: normalize(body?.cvc),
    email: normalize(body?.email),
  };

  const amount = Number(value.amount.replace(',', '.'));
  if (!Number.isFinite(amount) || amount <= 0 || amount > 100000) {
    errors.amount = 'Enter a valid positive amount.';
  }

  if (!/^[A-Z]{3}$/.test(value.currency)) {
    errors.currency = 'Enter a valid three-letter currency.';
  }

  if (value.orderId.length < 3 || value.orderId.length > 40) {
    errors.orderId = 'Order reference must be 3-40 characters.';
  }

  if (value.storeName.length < 2 || value.storeName.length > 80) {
    errors.storeName = 'Store name must be 2-80 characters.';
  }

  if (value.market.length < 2 || value.market.length > 30) {
    errors.market = 'Market must be 2-30 characters.';
  }

  const cardDigits = value.cardNumber.replace(/\D/g, '');
  if (!/^\d{13,19}$/.test(cardDigits)) {
    errors.cardNumber = 'Enter 13-19 card digits for demo validation.';
  }

  if (value.cardHolder.length < 3 || value.cardHolder.length > 80) {
    errors.cardHolder = 'Card holder must be 3-80 characters.';
  }

  if (!isValidExpiry(value.expiry)) {
    errors.expiry = 'Enter a future expiry date in MM/YY format.';
  }

  if (!/^\d{3,4}$/.test(value.cvc)) {
    errors.cvc = 'Enter a 3-4 digit CVC.';
  }

  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.email) || value.email.length > 120) {
    errors.email = 'Enter a valid email address.';
  }

  if (Object.keys(errors).length > 0) {
    return { ok: false, errors };
  }

  return { ok: true, value };
}

function normalize(value: unknown): string {
  return String(value ?? '').trim();
}

function isValidExpiry(raw: string): boolean {
  const match = raw.match(/^(\d{2})\/(\d{2})$/);
  if (!match) return false;

  const month = Number(match[1]);
  const year = Number(`20${match[2]}`);
  if (month < 1 || month > 12) return false;

  const expiryEnd = new Date(year, month, 0, 23, 59, 59, 999);
  return expiryEnd.getTime() >= Date.now();
}

function renderPaymentPrototypePage(): string {
  return `<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>Demo Payment Gateway</title>
  <style>
    *{box-sizing:border-box}
    :root{color-scheme:light;--ink:#172033;--muted:#6b7280;--line:#e6e8ef;--brand:#1f2937;--accent:#2563eb;--bg:#f4f6fb}
    body{margin:0;min-height:100vh;font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;background:radial-gradient(circle at top left,#dbeafe 0,#f4f6fb 34%,#eef2f7 100%);color:var(--ink)}
    button,input,select{font:inherit}
    .shell{min-height:100vh;display:grid;place-items:center;padding:38px 18px}
    .page{width:min(1040px,100%);display:grid;grid-template-columns:.84fr 1.16fr;gap:22px;align-items:stretch}
    .summary,.panel{background:rgba(255,255,255,.9);border:1px solid rgba(255,255,255,.78);box-shadow:0 24px 80px rgba(15,23,42,.14);backdrop-filter:blur(18px)}
    .summary{border-radius:28px;padding:30px;display:flex;flex-direction:column;justify-content:space-between;overflow:hidden;position:relative}
    .summary:before{content:"";position:absolute;inset:auto -90px -120px auto;width:250px;height:250px;border-radius:50%;background:linear-gradient(135deg,#93c5fd,#bfdbfe);opacity:.55}
    .brand{display:flex;align-items:center;gap:12px;margin-bottom:30px;position:relative}
    .brand-mark{width:42px;height:42px;border-radius:14px;background:#111827;color:#fff;display:grid;place-items:center;font-weight:800;letter-spacing:-.05em}
    .brand strong{display:block;font-size:16px}
    .brand span{display:block;font-size:12px;color:var(--muted);margin-top:2px}
    .amount-label{font-size:13px;color:var(--muted);text-transform:uppercase;letter-spacing:.12em;margin-bottom:10px}
    .amount{font-size:44px;line-height:1;font-weight:800;letter-spacing:-.06em;margin-bottom:26px}
    .meta{display:grid;gap:12px;position:relative}
    .meta-row{display:flex;justify-content:space-between;gap:14px;padding:14px 0;border-bottom:1px solid rgba(148,163,184,.22);font-size:14px}
    .meta-row span:first-child{color:var(--muted)}
    .meta-row strong{text-align:right}
    .notice{margin-top:26px;border-radius:18px;background:#eff6ff;border:1px solid #bfdbfe;color:#1e3a8a;padding:14px;font-size:13px;line-height:1.45;position:relative}
    .panel{border-radius:28px;padding:30px}
    h1{margin:0 0 8px;font-size:28px;letter-spacing:-.045em}
    .lead{margin:0 0 24px;color:var(--muted);font-size:15px;line-height:1.55}
    .grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
    .field{display:grid;gap:7px}
    .field.full{grid-column:1/-1}
    label{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#475569}
    input,select{width:100%;height:48px;border:1px solid var(--line);border-radius:14px;background:#fff;color:var(--ink);padding:0 14px;outline:none;transition:border .15s,box-shadow .15s}
    input:focus,select:focus{border-color:#93c5fd;box-shadow:0 0 0 4px rgba(59,130,246,.14)}
    .card-row{grid-template-columns:1fr 130px 100px}
    .actions{display:flex;align-items:center;gap:14px;margin-top:24px}
    .pay-btn{height:50px;border:0;border-radius:16px;background:#111827;color:#fff;font-weight:800;padding:0 24px;cursor:pointer;box-shadow:0 14px 28px rgba(17,24,39,.2);transition:transform .15s,box-shadow .15s,opacity .15s}
    .pay-btn:hover{transform:translateY(-1px);box-shadow:0 18px 36px rgba(17,24,39,.24)}
    .pay-btn:disabled{opacity:.65;cursor:wait;transform:none}
    .hint{font-size:12px;color:var(--muted);line-height:1.4}
    .error{display:none;margin-top:16px;border-radius:14px;background:#fef2f2;border:1px solid #fecaca;color:#991b1b;padding:12px 14px;font-size:13px;line-height:1.4}
    body.modal-open .shell{filter:blur(5px);transform:scale(.996)}
    .overlay{position:fixed;inset:0;display:none;align-items:center;justify-content:center;padding:20px;background:rgba(15,23,42,.56);z-index:50}
    .overlay.open{display:flex}
    .modal{width:min(440px,100%);background:#fff;border-radius:18px;padding:30px 30px 24px;box-shadow:0 34px 90px rgba(0,0,0,.32);text-align:center;color:#111827;animation:pop .18s ease-out}
    @keyframes pop{from{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}
    .secure{display:inline-flex;align-items:center;gap:8px;margin-bottom:20px;padding:8px 12px;border-radius:999px;background:#f8fafc;border:1px solid #e2e8f0;color:#475569;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.06em}
    .lock{width:18px;height:18px;border-radius:50%;display:grid;place-items:center;background:#16a34a;color:#fff;font-size:11px}
    .modal h2{margin:0 0 12px;font-size:24px;letter-spacing:-.035em}
    .modal p{margin:0;color:#64748b;font-size:15px;line-height:1.62}
    .understand{width:100%;height:48px;margin-top:26px;border:0;border-radius:10px;background:#111827;color:#fff;font-weight:800;letter-spacing:.02em;cursor:pointer}
    .modal-foot{margin-top:18px;padding-top:18px;border-top:1px solid #edf2f7;color:#94a3b8;font-size:12px;line-height:1.7}
    .modal-foot a{color:#64748b;text-decoration:none;font-weight:700}
    @media (max-width:860px){.page{grid-template-columns:1fr}.summary{min-height:360px}.card-row{grid-template-columns:1fr 1fr}.card-row .field:first-child{grid-column:1/-1}}
    @media (max-width:560px){.shell{padding:14px}.summary,.panel{border-radius:22px;padding:22px}.grid,.card-row{grid-template-columns:1fr}.amount{font-size:36px}.actions{align-items:stretch;flex-direction:column}.pay-btn{width:100%}}
  </style>
</head>
<body>
  <main class="shell" aria-labelledby="page-title">
    <section class="page">
      <aside class="summary" aria-label="Order summary">
        <div>
          <div class="brand">
            <div class="brand-mark">DP</div>
            <div><strong>DemoPay Gateway</strong><span>Local prototype environment</span></div>
          </div>
          <div class="amount-label">Kwota do zapłaty</div>
          <div class="amount" id="summaryAmount">129,99 PLN</div>
          <div class="meta">
            <div class="meta-row"><span>Zamówienie</span><strong id="summaryOrder">ORD-2026-001</strong></div>
            <div class="meta-row"><span>Sklep</span><strong id="summaryStore">Demo Store</strong></div>
            <div class="meta-row"><span>Rynek</span><strong id="summaryMarket">PL</strong></div>
            <div class="meta-row"><span>Status</span><strong>Weryfikacja testowa</strong></div>
          </div>
        </div>
        <div class="notice">Tryb demonstracyjny: formularz pokazuje przepływ płatności, ale backend nie przetwarza kart, nie wykonuje obciążeń i nie wysyła danych do zewnętrznych usług.</div>
      </aside>

      <section class="panel">
        <h1 id="page-title">Bezpieczna płatność kartą</h1>
        <p class="lead">Wprowadź dane testowe, aby zobaczyć prototyp ekranu weryfikacji. Używaj wyłącznie fikcyjnych danych.</p>
        <form id="paymentForm" novalidate>
          <div class="grid">
            <div class="field">
              <label for="amount">Kwota</label>
              <input id="amount" name="amount" inputmode="decimal" autocomplete="off" value="129.99" required>
            </div>
            <div class="field">
              <label for="currency">Waluta</label>
              <select id="currency" name="currency">
                <option>PLN</option>
                <option>EUR</option>
                <option>USD</option>
              </select>
            </div>
            <div class="field">
              <label for="orderId">Numer zamówienia</label>
              <input id="orderId" name="orderId" autocomplete="off" value="ORD-2026-001" required>
            </div>
            <div class="field">
              <label for="storeName">Sklep</label>
              <input id="storeName" name="storeName" autocomplete="organization" value="Demo Store" required>
            </div>
            <div class="field">
              <label for="market">Rynek</label>
              <input id="market" name="market" autocomplete="country" value="PL" required>
            </div>
            <div class="field">
              <label for="email">E-mail</label>
              <input id="email" name="email" type="email" autocomplete="email" placeholder="jan.kowalski@example.test" required>
            </div>
          </div>

          <div class="grid card-row" style="margin-top:16px">
            <div class="field">
              <label for="cardNumber">Numer karty</label>
              <input id="cardNumber" name="cardNumber" inputmode="numeric" autocomplete="off" placeholder="4242 4242 4242 4242" maxlength="23" required>
            </div>
            <div class="field">
              <label for="expiry">Data ważności</label>
              <input id="expiry" name="expiry" inputmode="numeric" autocomplete="off" placeholder="MM/YY" maxlength="5" required>
            </div>
            <div class="field">
              <label for="cvc">CVV/CVC</label>
              <input id="cvc" name="cvc" inputmode="numeric" autocomplete="off" placeholder="123" maxlength="4" required>
            </div>
            <div class="field full">
              <label for="cardHolder">Imię i nazwisko na karcie</label>
              <input id="cardHolder" name="cardHolder" autocomplete="off" placeholder="JAN KOWALSKI" required>
            </div>
          </div>

          <div id="formError" class="error" role="alert"></div>
          <div class="actions">
            <button class="pay-btn" type="submit">Zapłać testowo</button>
            <div class="hint">Backend zapisuje wyłącznie lokalny, zmaskowany ślad demonstracyjny i natychmiast odrzuca pełny numer karty oraz CVC.</div>
          </div>
        </form>
      </section>
    </section>
  </main>

  <div class="overlay" id="verifyOverlay" role="dialog" aria-modal="true" aria-labelledby="modalTitle" aria-describedby="modalText">
    <div class="modal">
      <div class="secure"><span class="lock">✓</span> Bezpieczne połączenie</div>
      <h2 id="modalTitle">Weryfikowanie danych...</h2>
      <p id="modalText">Trwa zestawianie szyfrowanego połączenia z bankiem. Ze względów bezpieczeństwa nie zamykaj tego okna i postępuj zgodnie z komunikatami wyświetlanymi na ekranie.</p>
      <button class="understand" id="understandBtn" type="button">ROZUMIEM</button>
      <div class="modal-foot">
        <div>DemoPay nie przechowuje pełnych danych karty w tym prototypie.</div>
        <div><a href="/payment-gateway">Regulamin</a> · <a href="/payment-gateway">Polityka prywatności</a> · Pomoc 24/7</div>
      </div>
    </div>
  </div>

  <script>
    (function(){
      var form = document.getElementById('paymentForm');
      var errorBox = document.getElementById('formError');
      var overlay = document.getElementById('verifyOverlay');
      var understand = document.getElementById('understandBtn');
      var amount = document.getElementById('amount');
      var currency = document.getElementById('currency');
      var orderId = document.getElementById('orderId');
      var storeName = document.getElementById('storeName');
      var market = document.getElementById('market');
      var cardNumber = document.getElementById('cardNumber');
      var expiry = document.getElementById('expiry');
      var cvc = document.getElementById('cvc');

      function updateSummary(){
        var numeric = Number(String(amount.value || '0').replace(',', '.'));
        document.getElementById('summaryAmount').textContent = (Number.isFinite(numeric) ? numeric.toFixed(2).replace('.', ',') : '0,00') + ' ' + currency.value;
        document.getElementById('summaryOrder').textContent = orderId.value || 'ORD-2026-001';
        document.getElementById('summaryStore').textContent = storeName.value || 'Demo Store';
        document.getElementById('summaryMarket').textContent = market.value || 'PL';
      }

      function showError(message){
        errorBox.textContent = message;
        errorBox.style.display = 'block';
      }

      function clearError(){
        errorBox.textContent = '';
        errorBox.style.display = 'none';
      }

      function openModal(){
        overlay.classList.add('open');
        document.body.classList.add('modal-open');
        understand.focus();
      }

      function closeModal(){
        overlay.classList.remove('open');
        document.body.classList.remove('modal-open');
      }

      cardNumber.addEventListener('input', function(){
        var digits = cardNumber.value.replace(/\\D/g, '').slice(0, 19);
        cardNumber.value = digits.replace(/(\\d{4})(?=\\d)/g, '$1 ');
      });

      expiry.addEventListener('input', function(){
        var digits = expiry.value.replace(/\\D/g, '').slice(0, 4);
        expiry.value = digits.length > 2 ? digits.slice(0, 2) + '/' + digits.slice(2) : digits;
      });

      cvc.addEventListener('input', function(){
        cvc.value = cvc.value.replace(/\\D/g, '').slice(0, 4);
      });

      [amount, currency, orderId, storeName, market].forEach(function(el){
        el.addEventListener('input', updateSummary);
        el.addEventListener('change', updateSummary);
      });

      understand.addEventListener('click', closeModal);

      form.addEventListener('submit', function(event){
        event.preventDefault();
        clearError();
        var button = form.querySelector('button[type="submit"]');
        button.disabled = true;

        var payload = Object.fromEntries(new FormData(form).entries());
        fetch('/api/prototype/payments', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(payload)
        })
          .then(function(response){
            return response.json().then(function(data){
              if (!response.ok) {
                var details = data && data.errors ? Object.values(data.errors).join(' ') : 'Sprawdź dane formularza.';
                throw new Error(details);
              }
              return data;
            });
          })
          .then(function(){
            openModal();
            form.reset();
            amount.value = '129.99';
            currency.value = 'PLN';
            orderId.value = 'ORD-2026-001';
            storeName.value = 'Demo Store';
            market.value = 'PL';
            updateSummary();
          })
          .catch(function(error){
            showError(error.message || 'Nie udało się obsłużyć zgłoszenia testowego.');
          })
          .finally(function(){
            button.disabled = false;
          });
      });

      updateSummary();
    })();
  </script>
</body>
</html>`;
}
