/**
 * Workspace-owned domains.
 *
 * GET  /api/workspaces/[slug]/domains  — list domains owned by the workspace
 * POST /api/workspaces/[slug]/domains  — register a domain through OpenSRS
 *
 * POST body:
 *   {
 *     domain: "example.com",
 *     period?: 1,
 *     whoisPrivacy?: true,
 *     contact: {
 *       first_name, last_name, org_name?,
 *       address1, address2?, city, state, country, postal_code,
 *       phone, fax?, email
 *     },
 *     nameservers?: string[],
 *     ca?: { cprCategory, legalType }   // required for .ca
 *   }
 *
 * Safety rails:
 *   - `OPENSRS_MODE=test` is strongly recommended until we've verified live
 *     registration end-to-end. The handler reads the current mode from env
 *     and echoes it in the response so agents can tell.
 *   - We guard against duplicate POSTs by reusing an existing `pending` row
 *     for the same (workspace, domain) pair — caller can retry safely.
 */

import { NextResponse } from 'next/server';
import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth';
import {
  domainTld,
  registerDomain,
  OpenSrsError,
  minPeriodFor,
  type RegistrationContact,
} from '@/lib/opensrs';
import {
  createDomainIntent,
  getDomainForWorkspace,
  listDomainsForWorkspace,
  markDomainFailed,
  markDomainRegistered,
  recordDomainEvent,
  recordLedgerEntry,
} from '@/lib/domains';

export async function GET(
  request: Request,
  { params }: { params: Promise<{ slug: string }> },
) {
  const { slug } = await params;
  const principal = await requireWorkspacePrincipal(request, { targetSlug: slug });
  if (principal instanceof NextResponse) return principal;

  const rows = await listDomainsForWorkspace(principal.workspace.id);
  return NextResponse.json({
    workspace: { slug: principal.workspace.slug },
    mode: process.env.OPENSRS_MODE ?? 'test',
    domains: rows.map(r => ({
      id: r.id,
      domain: r.domain,
      tld: r.tld,
      status: r.status,
      registrar: r.registrar,
      periodYears: r.period_years,
      whoisPrivacy: r.whois_privacy,
      autoRenew: r.auto_renew,
      registeredAt: r.registered_at,
      expiresAt: r.expires_at,
      dnsProvider: r.dns_provider,
      dnsNameservers: r.dns_nameservers,
      pricePaidCents: r.price_paid_cents,
      priceCurrency: r.price_currency,
      createdAt: r.created_at,
    })),
  });
}

interface PostBody {
  domain?: string;
  period?: number;
  whoisPrivacy?: boolean;
  contact?: RegistrationContact;
  nameservers?: string[];
  ca?: { cprCategory: string; legalType: string };
}

export async function POST(
  request: Request,
  { params }: { params: Promise<{ slug: string }> },
) {
  const { slug } = await params;
  const principal = await requireWorkspacePrincipal(request, { targetSlug: slug });
  if (principal instanceof NextResponse) return principal;

  let body: PostBody = {};
  try {
    body = await request.json();
  } catch {
    return NextResponse.json({ error: 'Invalid JSON body' }, { status: 400 });
  }

  const raw = (body.domain ?? '').toString().trim().toLowerCase()
    .replace(/^https?:\/\//, '').replace(/\/+$/, '');
  if (!raw || !/^[a-z0-9-]+(\.[a-z0-9-]+)+$/i.test(raw)) {
    return NextResponse.json({ error: '`domain` is required and must be a valid hostname' }, { status: 400 });
  }
  const contactValidation = validateContact(body.contact);
  if (contactValidation) return contactValidation;

  const tld = domainTld(raw);
  if (tld === 'ca' && !body.ca) {
    return NextResponse.json(
      { error: '.ca registration requires { ca: { cprCategory, legalType } }' },
      { status: 400 },
    );
  }

  const period = minPeriodFor(tld, typeof body.period === 'number' ? body.period : 1);

  // Reuse an existing pending intent to keep POSTs idempotent.
  let intent = await getDomainForWorkspace(principal.workspace.id, raw);
  if (intent && intent.status === 'active') {
    return NextResponse.json(
      { error: `Domain ${raw} is already registered in this workspace`, domainId: intent.id },
      { status: 409 },
    );
  }
  if (!intent) {
    intent = await createDomainIntent({
      workspaceId: principal.workspace.id,
      domain: raw,
      createdBy: principal.userId,
      periodYears: period,
      whoisPrivacy: body.whoisPrivacy ?? true,
    });
  }

  await recordDomainEvent({
    domainId: intent.id,
    workspaceId: principal.workspace.id,
    type: 'register.attempt',
    payload: { period, mode: process.env.OPENSRS_MODE ?? 'test' },
  });

  try {
    const result = await registerDomain({
      domain: raw,
      period,
      contact: body.contact as RegistrationContact,
      nameservers: body.nameservers,
      whoisPrivacy: body.whoisPrivacy ?? true,
      ca: body.ca,
    });

    const priceCents: number | null = null; // registrar price is captured at search time; later we'll pull the real reseller debit from get_balance_changes
    const currency = process.env.OPENSRS_CURRENCY ?? 'CAD';

    const updated = await markDomainRegistered({
      domainId: intent.id,
      registrarOrderId: result.orderId,
      registrarUsername: result.regUsername,
      registrarPassword: result.regPassword,
      periodYears: period,
      pricePaidCents: priceCents,
      priceCurrency: currency,
      registeredAt: new Date(),
      expiresAt: new Date(Date.now() + period * 365 * 24 * 60 * 60 * 1000),
    });

    if (priceCents) {
      await recordLedgerEntry({
        workspaceId: principal.workspace.id,
        kind: 'debit',
        amountCents: priceCents,
        currency,
        refType: 'domain.register',
        refId: intent.id,
        note: `Register ${raw} (${period}y)`,
      });
    }

    await recordDomainEvent({
      domainId: intent.id,
      workspaceId: principal.workspace.id,
      type: 'register.success',
      payload: { orderId: result.orderId, period, mode: process.env.OPENSRS_MODE ?? 'test' },
    });

    return NextResponse.json({
      ok: true,
      mode: process.env.OPENSRS_MODE ?? 'test',
      domain: {
        id: updated.id,
        domain: updated.domain,
        tld: updated.tld,
        status: updated.status,
        periodYears: updated.period_years,
        registeredAt: updated.registered_at,
        expiresAt: updated.expires_at,
        registrarOrderId: updated.registrar_order_id,
      },
    });
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    await markDomainFailed(intent.id, message);
    if (err instanceof OpenSrsError) {
      return NextResponse.json(
        { error: 'Registration failed', registrarCode: err.code, details: err.message },
        { status: 502 },
      );
    }
    return NextResponse.json(
      { error: 'Registration failed', details: message },
      { status: 500 },
    );
  }
}

function validateContact(c?: RegistrationContact): NextResponse | null {
  if (!c) return NextResponse.json({ error: '`contact` is required' }, { status: 400 });
  const required: (keyof RegistrationContact)[] = [
    'first_name', 'last_name', 'address1', 'city', 'state', 'country', 'postal_code', 'phone', 'email',
  ];
  for (const k of required) {
    if (!c[k] || typeof c[k] !== 'string' || !(c[k] as string).trim()) {
      return NextResponse.json({ error: `contact.${k} is required` }, { status: 400 });
    }
  }
  if (!/^[A-Z]{2}$/.test(c.country)) {
    return NextResponse.json({ error: 'contact.country must be an ISO 3166-1 alpha-2 code' }, { status: 400 });
  }
  if (!/@/.test(c.email)) {
    return NextResponse.json({ error: 'contact.email must be a valid email' }, { status: 400 });
  }
  return null;
}
