import { Router } from 'express';
import { getUserById } from '../cqrs';
import { ServerPayload } from '../cqrs/types';
import { getActiveServerInvite } from '../services/server-access.service';
import {
  buildAppInviteUrl,
  buildBrowserInviteUrl,
  buildInviteUrl,
  getRequestOrigin
} from './invite-utils';

export const invitesApiRouter = Router();
export const invitePageRouter = Router();

async function enrichServer(server: ServerPayload, sourceUrl: string) {
  const owner = await getUserById(server.ownerId);
  const { passwordHash, ...publicServer } = server;

  return {
    ...publicServer,
    hasPassword: server.hasPassword ?? !!passwordHash,
    ownerName: owner?.displayName,
    sourceUrl,
    userCount: server.currentUsers
  };
}

function renderInvitePage(options: {
  appUrl?: string;
  browserUrl?: string;
  error?: string;
  expiresAt?: number;
  inviteUrl?: string;
  isExpired: boolean;
  ownerName?: string;
  serverDescription?: string;
  serverName: string;
}) {
  const expiryLabel = options.expiresAt
    ? new Date(options.expiresAt).toLocaleString('en-US', {
      dateStyle: 'medium',
      timeStyle: 'short'
    })
    : null;
  const statusLabel = options.isExpired ? 'Expired' : 'Active';
  const statusColor = options.isExpired ? '#f87171' : '#4ade80';
  const buttonOpacity = options.isExpired ? 'opacity:0.5;pointer-events:none;' : '';
  const errorBlock = options.error
    ? `<div class="notice notice-error">${options.error}</div>`
    : '';
  const description = options.serverDescription
    ? `<p class="description">${options.serverDescription}</p>`
    : '<p class="description">You have been invited to join a Toju server.</p>';

  return `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Invite to ${options.serverName}</title>
    <style>
      :root {
        color-scheme: dark;
        --bg: #050816;
        --bg-soft: rgba(11, 18, 42, 0.78);
        --card: rgba(15, 23, 42, 0.92);
        --border: rgba(148, 163, 184, 0.18);
        --text: #f8fafc;
        --muted: #cbd5e1;
        --primary: #8b5cf6;
        --primary-soft: rgba(139, 92, 246, 0.16);
        --secondary: rgba(148, 163, 184, 0.16);
      }
      * { box-sizing: border-box; }
      body {
        margin: 0;
        min-height: 100vh;
        font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
        color: var(--text);
        background:
          radial-gradient(circle at top left, rgba(59, 130, 246, 0.28), transparent 32%),
          radial-gradient(circle at top right, rgba(139, 92, 246, 0.24), transparent 30%),
          linear-gradient(180deg, #050816 0%, #0b1120 100%);
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 32px 20px;
      }
      .shell {
        width: min(100%, 760px);
        border: 1px solid var(--border);
        border-radius: 28px;
        background: var(--bg-soft);
        backdrop-filter: blur(22px);
        box-shadow: 0 30px 90px rgba(15, 23, 42, 0.5);
        overflow: hidden;
      }
      .hero {
        padding: 36px 36px 28px;
        border-bottom: 1px solid var(--border);
        background: linear-gradient(180deg, rgba(15, 23, 42, 0.8), rgba(15, 23, 42, 0.55));
      }
      .eyebrow {
        display: inline-flex;
        align-items: center;
        gap: 10px;
        padding: 8px 14px;
        border-radius: 999px;
        font-size: 12px;
        font-weight: 700;
        letter-spacing: 0.18em;
        text-transform: uppercase;
        color: var(--muted);
        background: var(--secondary);
      }
      .status-dot {
        width: 8px;
        height: 8px;
        border-radius: 999px;
        background: ${statusColor};
        box-shadow: 0 0 0 6px color-mix(in srgb, ${statusColor} 18%, transparent);
      }
      h1 {
        margin: 18px 0 10px;
        font-size: clamp(2rem, 3vw, 3.25rem);
        line-height: 1.05;
      }
      .description {
        margin: 0;
        color: var(--muted);
        font-size: 1rem;
        line-height: 1.6;
        max-width: 44rem;
      }
      .content {
        display: grid;
        gap: 20px;
        padding: 28px 36px 36px;
      }
      .meta-grid {
        display: grid;
        gap: 16px;
        grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      }
      .meta-card {
        border: 1px solid var(--border);
        border-radius: 18px;
        background: var(--card);
        padding: 18px;
      }
      .meta-label {
        font-size: 11px;
        letter-spacing: 0.18em;
        text-transform: uppercase;
        color: var(--muted);
        opacity: 0.8;
      }
      .meta-value {
        margin-top: 10px;
        font-size: 1rem;
        font-weight: 600;
        color: var(--text);
      }
      .actions {
        display: grid;
        gap: 14px;
        grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
      }
      .button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 10px;
        min-height: 56px;
        padding: 0 18px;
        border-radius: 16px;
        border: 1px solid transparent;
        color: var(--text);
        text-decoration: none;
        font-weight: 700;
        transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
      }
      .button:hover {
        transform: translateY(-1px);
      }
      .button-primary {
        background: linear-gradient(135deg, #8b5cf6, #6366f1);
        box-shadow: 0 18px 36px rgba(99, 102, 241, 0.28);
      }
      .button-secondary {
        border-color: var(--border);
        background: rgba(15, 23, 42, 0.8);
      }
      .notice {
        border-radius: 16px;
        padding: 14px 16px;
        border: 1px solid var(--border);
        background: rgba(15, 23, 42, 0.72);
        color: var(--muted);
        line-height: 1.6;
      }
      .notice-error {
        border-color: rgba(248, 113, 113, 0.32);
        background: rgba(127, 29, 29, 0.18);
        color: #fecaca;
      }
      .footer {
        display: flex;
        flex-wrap: wrap;
        gap: 12px 18px;
        align-items: center;
        justify-content: space-between;
        color: var(--muted);
        font-size: 0.95rem;
      }
      .footer a {
        color: #c4b5fd;
        text-decoration: none;
      }
      .footer a:hover {
        text-decoration: underline;
      }
      code {
        font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
        color: #ddd6fe;
      }
      @media (max-width: 640px) {
        .hero, .content { padding-inline: 22px; }
      }
    </style>
  </head>
  <body>
    <main class="shell">
      <section class="hero">
        <div class="eyebrow"><span class="status-dot"></span>${statusLabel} invite</div>
        <h1>Join ${options.serverName}</h1>
        ${description}
      </section>

      <section class="content">
        ${errorBlock}
        <div class="meta-grid">
          <article class="meta-card">
            <div class="meta-label">Server</div>
            <div class="meta-value">${options.serverName}</div>
          </article>
          <article class="meta-card">
            <div class="meta-label">Owner</div>
            <div class="meta-value">${options.ownerName || 'Unknown'}</div>
          </article>
          <article class="meta-card">
            <div class="meta-label">Expires</div>
            <div class="meta-value">${expiryLabel || 'Expired'}</div>
          </article>
        </div>

        <div class="actions" style="${buttonOpacity}">
          <a class="button button-primary" href="${options.browserUrl || '#'}">Join in browser</a>
          <a class="button button-secondary" href="${options.appUrl || '#'}">Open with Toju</a>
        </div>

        <div class="notice">
          Invite links bypass private and password restrictions, but banned users still cannot join.
          If Toju is not installed yet, use the desktop button after installing from <a href="https://toju.app/downloads">toju.app/downloads</a>.
        </div>

        <div class="footer">
          <span>Share link: <code>${options.inviteUrl || 'Unavailable'}</code></span>
          <a href="https://toju.app/downloads">Download Toju</a>
        </div>
      </section>
    </main>
  </body>
</html>`;
}

invitesApiRouter.get('/:id', async (req, res) => {
  const signalOrigin = getRequestOrigin(req);
  const bundle = await getActiveServerInvite(req.params['id']);

  if (!bundle) {
    return res.status(404).json({ error: 'Invite link has expired or is invalid', errorCode: 'INVITE_EXPIRED' });
  }

  const server = bundle.server;

  res.json({
    id: bundle.invite.id,
    serverId: bundle.invite.serverId,
    createdAt: bundle.invite.createdAt,
    expiresAt: bundle.invite.expiresAt,
    inviteUrl: buildInviteUrl(signalOrigin, bundle.invite.id),
    browserUrl: buildBrowserInviteUrl(signalOrigin, bundle.invite.id),
    appUrl: buildAppInviteUrl(signalOrigin, bundle.invite.id),
    sourceUrl: signalOrigin,
    createdBy: bundle.invite.createdBy,
    createdByDisplayName: bundle.invite.createdByDisplayName ?? undefined,
    isExpired: bundle.invite.expiresAt <= Date.now(),
    server: await enrichServer(server, signalOrigin)
  });
});

invitePageRouter.get('/:id', async (req, res) => {
  const signalOrigin = getRequestOrigin(req);
  const bundle = await getActiveServerInvite(req.params['id']);

  if (!bundle) {
    res.status(404).send(renderInvitePage({
      error: 'This invite has expired or is no longer available.',
      isExpired: true,
      serverName: 'Toju server'
    }));

    return;
  }

  const server = bundle.server;
  const owner = await getUserById(server.ownerId);

  res.send(renderInvitePage({
    serverName: server.name,
    serverDescription: server.description,
    ownerName: owner?.displayName,
    expiresAt: bundle.invite.expiresAt,
    inviteUrl: buildInviteUrl(signalOrigin, bundle.invite.id),
    browserUrl: buildBrowserInviteUrl(signalOrigin, bundle.invite.id),
    appUrl: buildAppInviteUrl(signalOrigin, bundle.invite.id),
    isExpired: bundle.invite.expiresAt <= Date.now()
  }));
});
