/**
 * GET  /api/route53/zones/:zoneId/records — list mirrored resource record
 *   sets in a hosted zone. Optional `?type=` and `?search=` filters.
 *   requireAuth() gated.
 *
 * POST /api/route53/zones/:zoneId/records — create a resource record set.
 *   requireAdmin() gated (D-04). Sequence identical to PATCH/DELETE in
 *   ./[recordId]/route.ts:
 *    1. requireAdmin() (D-04)
 *    2. isRoute53Configured() -> 503
 *    3. parse + validateRecordWrite() (D-01, before any AWS command)
 *    4. beforeValue = null; loadMirrorRecord must be null or 409
 *    5. createPendingAuditLog before any AWS call (D-07/SC-3)
 *    6. submitRecordChange + pollChangeStatus -> markAuditCommitted ->
 *       insertPulseCrudHistory -> upsertMirrorRecord -> 201
 *    7. catch -> sanitizeAwsError -> markAuditFailed -> 502 (no history row)
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, requireAdmin } from '@/lib/auth-utils';
import postgresClient from '@/lib/services/postgres-client';
import { isRoute53Configured } from '@/lib/services/route53-factory';
import { validateRecordWrite, sanitizeAwsError } from '@/lib/services/route53-record-validation';
import {
  createPendingAuditLog,
  markAuditCommitted,
  markAuditFailed,
  insertPulseCrudHistory,
  upsertMirrorRecord,
  loadMirrorRecord,
} from '@/lib/services/route53-write-persistence';
import { submitRecordChange, pollChangeStatus } from '@/lib/services/route53-change-submit';
import { buildRecordKey } from '@/lib/services/route53-record-key';
import type { Route53Record } from '@/lib/types/route53';

interface RecordRow {
  record_key: string;
  zone_id: string;
  name: string;
  type: string;
  set_identifier: string | null;
  ttl: number | null;
  resource_records: Array<{ value: string }> | null;
  alias_target: Record<string, unknown> | null;
  synced_at: string;
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ zoneId: string }> }
) {
  const { error } = await requireAuth();
  if (error) return error;

  try {
    const { zoneId } = await params;
    const url = request.nextUrl;
    const type = url.searchParams.get('type');
    const search = url.searchParams.get('search');

    const conditions = ['zone_id = $1', 'is_deleted = false'];
    const queryParams: unknown[] = [zoneId];

    if (type) {
      queryParams.push(type.toUpperCase());
      conditions.push(`type = $${queryParams.length}`);
    }
    if (search) {
      queryParams.push(`%${search}%`);
      conditions.push(`name ILIKE $${queryParams.length}`);
    }

    const res = await postgresClient.query<RecordRow>(
      `SELECT record_key, zone_id, name, type, set_identifier, ttl, resource_records, alias_target, synced_at
         FROM route53_records
        WHERE ${conditions.join(' AND ')}
        ORDER BY name, type`,
      queryParams
    );

    const records: Route53Record[] = res.rows.map((row) => ({
      recordKey: row.record_key,
      zoneId: row.zone_id,
      name: row.name,
      type: row.type,
      setIdentifier: row.set_identifier,
      ttl: row.ttl,
      resourceRecords: row.resource_records,
      aliasTarget: row.alias_target,
      syncedAt: row.synced_at,
      isDeleted: false,
    }));

    return NextResponse.json({ items: records });
  } catch (err) {
    console.error('[ROUTE53-RECORDS] Failed to list records:', err);
    return NextResponse.json(
      { error: err instanceof Error ? err.message : 'Failed to fetch Route 53 records' },
      { status: 500 }
    );
  }
}

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ zoneId: string }> }
) {
  const { session, error } = await requireAdmin();
  if (error) return error;

  if (!isRoute53Configured()) {
    return NextResponse.json(
      {
        error: 'Route 53 not configured',
        message: 'AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must be set to write Route 53 records',
      },
      { status: 503 }
    );
  }

  const { zoneId } = await params;
  const body = await request.json().catch(() => ({}));

  const validated = validateRecordWrite(body);
  if (!validated.ok) {
    return NextResponse.json({ error: 'Invalid record', message: validated.reason }, { status: 400 });
  }
  const { name, type, ttl, resourceRecords } = validated.value;
  const setIdentifier: string | null =
    typeof body.setIdentifier === 'string' && body.setIdentifier.trim().length > 0
      ? body.setIdentifier.trim()
      : null;

  const recordKey = buildRecordKey({ zoneId, name, type, setIdentifier });

  const existing = await loadMirrorRecord(recordKey);
  if (existing) {
    return NextResponse.json({ error: 'Record already exists' }, { status: 409 });
  }

  const afterValue = { name, type, ttl, setIdentifier, resourceRecords };
  const audit = await createPendingAuditLog({
    operation: 'create',
    zoneId,
    recordKey,
    recordName: name,
    recordType: type,
    beforeValue: null,
    afterValue,
    performedByUserId: session!.user.id,
    performedByEmail: session!.user.email,
  });

  try {
    const { changeId, awsResponse } = await submitRecordChange({
      zoneId,
      action: 'CREATE',
      recordSet: { name, type, ttl, resourceRecords, setIdentifier },
    });
    const propagationStatus = changeId ? await pollChangeStatus(changeId) : 'PENDING';

    await markAuditCommitted(audit.id, changeId, propagationStatus, awsResponse);
    await insertPulseCrudHistory({
      zoneId,
      recordKey,
      recordName: name,
      recordType: type,
      changeAction: 'create',
      beforeValue: null,
      afterValue,
      changedByUserId: session!.user.id,
      changedByEmail: session!.user.email,
      auditLogId: audit.id,
    });
    await upsertMirrorRecord({
      recordKey,
      zoneId,
      name,
      type,
      setIdentifier,
      ttl,
      resourceRecords,
      aliasTarget: null,
      rawPayload: afterValue,
    });

    return NextResponse.json(
      { auditId: audit.id, status: 'committed', propagationStatus, record: afterValue },
      { status: 201 }
    );
  } catch (err) {
    const message = sanitizeAwsError(err);
    console.error('[ROUTE53-WRITE] create failed:', message);
    await markAuditFailed(audit.id, err);
    return NextResponse.json(
      { auditId: audit.id, status: 'failed', error: 'Route 53 write failed', message },
      { status: 502 }
    );
  }
}
