/**
 * Per-port synthetic seed builder for "every pipeline stage" coverage.
 *
 * The realistic seed in `seed-data.ts` mirrors the legacy NocoDB shape;
 * this one is purpose-built for thoroughly exercising the CRM. Every
 * pipeline stage gets at least one client, plus a handful of edge-case
 * fixtures (multi-interest, signed-EOI, archived with metadata, hard-
 * delete-eligible, company member, yacht owner).
 *
 * Berths come from the same NocoDB snapshot so the public berth API
 * still has data; the synthetic clients link to specific moorings so
 * the under_offer / sold derivations are deterministic.
 *
 * Idempotent: skips if the port already has clients seeded.
 *
 * Run via `pnpm db:seed:synthetic`.
 */

import { eq } from 'drizzle-orm';

import { db } from './index';
import { withTransaction } from './utils';
import {
  clients,
  clientContacts,
  clientAddresses,
  companies,
  companyMemberships,
  companyAddresses,
  yachts,
  yachtOwnershipHistory,
  berths,
  berthTenancies,
  interests,
  interestBerths,
} from './schema';
import { residentialClients, residentialInterests } from './schema';
import { SUPER_ADMIN_USER_ID } from './seed-bootstrap';
import berthSnapshot from './seed-data/berths.json';
import type { PipelineStage } from '@/lib/constants';
import type { ArchiveMetadata } from '@/lib/services/client-archive.service';

type SeedBerth = {
  legacyId: number;
  mooringNumber: string;
  area: string | null;
  status: 'available' | 'under_offer' | 'sold';
  lengthFt: number | null;
  widthFt: number | null;
  draftFt: number | null;
  lengthM: number | null;
  widthM: number | null;
  draftM: number | null;
  widthIsMinimum: boolean;
  nominalBoatSize: number | null;
  nominalBoatSizeM: number | null;
  waterDepth: number | null;
  waterDepthM: number | null;
  waterDepthIsMinimum: boolean;
  sidePontoon: string | null;
  powerCapacity: number | null;
  voltage: number | null;
  mooringType: string | null;
  cleatType: string | null;
  cleatCapacity: string | null;
  bollardType: string | null;
  bollardCapacity: string | null;
  access: string | null;
  price: number | null;
  bowFacing: string | null;
  berthApproved: boolean;
  statusOverrideMode: string | null;
};
const BERTH_SNAPSHOT = berthSnapshot as SeedBerth[];

function daysAgo(n: number): Date {
  return new Date(Date.now() - n * 86_400_000);
}

export interface SyntheticSeedSummary {
  berths: number;
  clients: number;
  interests: number;
  companies: number;
  yachts: number;
  residentialClients: number;
}

interface SyntheticClientSpec {
  /** Stable identifier used by Playwright selectors and intra-seed wiring
   *  (memberships, yachts, etc.). Decoupled from the display name so the
   *  rendered list looks like real client data, not test fixtures. */
  tag: string;
  fullName: string;
  email: string;
  phone: string;
  countryIso: string;
  city: string;
  street: string;
  postalCode: string;
  /** Pipeline stage of the (single) interest. Omit for archived-only clients. */
  stage?: PipelineStage;
  /** Sub-status badges for the doc-signing stages (eoi / reservation / contract).
   *  Only meaningful when stage matches; otherwise null/undefined. */
  eoiDocStatus?: 'sent' | 'signed';
  reservationDocStatus?: 'sent' | 'signed';
  contractDocStatus?: 'sent' | 'signed';
  /** Index into BERTH_SNAPSHOT for the primary linked berth. */
  berthIdx?: number;
  /** Mark interest as won/lost when stage = contract+signed. */
  outcome?: 'won' | 'lost_unqualified' | 'lost_no_response';
  /** Archive the CLIENT after creation. When 'rich', fabricate
   *  archive_metadata so the smart-restore wizard surfaces reversals. */
  archive?: 'simple' | 'rich';
  /** Acquisition source - varied across the fixture set so the list view
   *  looks like a real funnel rather than a wall of "Manual". */
  source?: 'website' | 'manual' | 'referral' | 'broker';
  /** How long ago (in days) this client record was created. Spreads the
   *  "Created" column across realistic timestamps so list pages look like
   *  a real CRM with months of history rather than 12 rows all stamped
   *  with today's date. */
  createdDaysAgo?: number;
}

/**
 * Each spec produces exactly one client + one interest at the given
 * stage. Clients are tagged so a Playwright test can locate them by
 * either name (full name) or tag (substring after the dash).
 *
 * Berth indices map deterministically into the NocoDB snapshot which is
 * pre-sorted: idx 0..4 available, 5..9 under_offer, 10..11 sold.
 */
/**
 * Believable demo dataset - names, emails, phone numbers, addresses, and
 * acquisition sources read like a real marina's prospect list rather
 * than fixtures keyed on enum names. The `tag` field still carries the
 * stage/role identity for selectors and intra-seed wiring; nothing in
 * the rendered UI references it.
 *
 * Spread across acquisition sources, ages (3–280 days), and countries
 * so list / dashboard / kanban surfaces look populated and natural.
 */
const PIPELINE_CLIENTS: SyntheticClientSpec[] = [
  {
    tag: 'open',
    fullName: 'Olivia Sinclair',
    email: 'olivia.sinclair@gmail.com',
    phone: '+44 7700 900142',
    countryIso: 'GB',
    city: 'London',
    street: '14 Cheyne Walk',
    postalCode: 'SW3 5RA',
    stage: 'enquiry',
    source: 'website',
    createdDaysAgo: 4,
    // Open stage: no berth link yet
  },
  {
    tag: 'details',
    fullName: 'Daniel Whitaker',
    email: 'daniel.whitaker@outlook.com',
    phone: '+1 305 555 0182',
    countryIso: 'US',
    city: 'Miami',
    street: '880 Brickell Bay Drive',
    postalCode: '33131',
    stage: 'enquiry',
    berthIdx: 0,
    source: 'broker',
    createdDaysAgo: 12,
  },
  {
    tag: 'comms',
    fullName: 'Carla Mendoza',
    email: 'carla.mendoza@gmail.com',
    phone: '+34 971 555 028',
    countryIso: 'ES',
    city: 'Palma de Mallorca',
    street: 'Carrer de Sant Magí 23',
    postalCode: '07013',
    stage: 'qualified',
    berthIdx: 5,
    source: 'referral',
    createdDaysAgo: 28,
  },
  {
    tag: 'eoi-sent',
    fullName: 'Marco Bianchi',
    email: 'marco.bianchi@libero.it',
    phone: '+39 010 8740 215',
    countryIso: 'IT',
    city: 'Genoa',
    street: 'Via XX Settembre 47',
    postalCode: '16121',
    stage: 'eoi',
    eoiDocStatus: 'sent',
    berthIdx: 6,
    source: 'broker',
    createdDaysAgo: 45,
  },
  {
    tag: 'eoi-signed',
    fullName: 'Sara Laurent',
    email: 'sara.laurent@orange.fr',
    phone: '+33 4 93 92 18 47',
    countryIso: 'FR',
    city: 'Nice',
    street: '8 Promenade des Anglais',
    postalCode: '06000',
    stage: 'eoi',
    eoiDocStatus: 'signed',
    berthIdx: 7,
    source: 'website',
    createdDaysAgo: 72,
  },
  {
    tag: 'deposit',
    fullName: 'Nikolas Papadakis',
    email: 'n.papadakis@gmail.com',
    phone: '+30 210 8945 612',
    countryIso: 'GR',
    city: 'Athens',
    street: 'Vouliagmenis Avenue 142',
    postalCode: '16674',
    stage: 'deposit_paid',
    berthIdx: 8,
    source: 'referral',
    createdDaysAgo: 95,
  },
  {
    tag: 'contract-sent',
    fullName: 'Connor Murphy',
    email: 'connor.murphy@me.com',
    phone: '+353 1 555 0184',
    countryIso: 'IE',
    city: 'Dublin',
    street: '12 Merrion Square North',
    postalCode: 'D02 E2X3',
    stage: 'contract',
    contractDocStatus: 'sent',
    berthIdx: 9,
    source: 'manual',
    createdDaysAgo: 118,
  },
  {
    tag: 'contract-signed',
    fullName: 'Carmen Costa',
    email: 'carmen.costa@sapo.pt',
    phone: '+351 21 386 4520',
    countryIso: 'PT',
    city: 'Lisbon',
    street: 'Rua Garrett 88',
    postalCode: '1200-205',
    stage: 'contract',
    contractDocStatus: 'signed',
    berthIdx: 4,
    source: 'broker',
    createdDaysAgo: 156,
  },
  {
    tag: 'completed-won',
    fullName: 'Carlos Vega',
    email: 'carlos.vega@gmail.com',
    phone: '+507 6612 4485',
    countryIso: 'PA',
    city: 'Panama City',
    street: 'Calle 50, Torre Banistmo Piso 18',
    postalCode: '0816',
    stage: 'contract',
    contractDocStatus: 'signed',
    berthIdx: 10,
    outcome: 'won',
    source: 'referral',
    createdDaysAgo: 245,
  },
  {
    tag: 'completed-lost',
    fullName: 'Hannah Schmidt',
    email: 'hannah.schmidt@gmx.de',
    phone: '+49 40 4286 9152',
    countryIso: 'DE',
    city: 'Hamburg',
    street: 'Alsterufer 28',
    postalCode: '20354',
    stage: 'enquiry',
    berthIdx: 1,
    outcome: 'lost_unqualified',
    source: 'website',
    createdDaysAgo: 84,
  },
  {
    tag: 'archived-simple',
    fullName: 'Anna de Jong',
    email: 'anna.dejong@kpn.nl',
    phone: '+31 20 624 7185',
    countryIso: 'NL',
    city: 'Amsterdam',
    street: 'Herengracht 412',
    postalCode: '1017 BX',
    archive: 'simple',
    source: 'website',
    createdDaysAgo: 201,
  },
  {
    tag: 'archived-rich',
    fullName: 'Rita Vermeulen',
    email: 'rita.vermeulen@telenet.be',
    phone: '+32 3 226 8420',
    countryIso: 'BE',
    city: 'Antwerp',
    street: 'Meir 102',
    postalCode: '2000',
    archive: 'rich',
    source: 'broker',
    createdDaysAgo: 280,
  },
];

export async function seedSyntheticPortData(
  portId: string,
  portSlug: string,
): Promise<SyntheticSeedSummary | null> {
  const existing = await db
    .select({ id: clients.id })
    .from(clients)
    .where(eq(clients.portId, portId))
    .limit(1);
  if (existing.length > 0) {
    console.log(`  [${portSlug}] already seeded (clients exist), skipping.`);
    return null;
  }

  return withTransaction(async (tx) => {
    // ── 1. Berths ───────────────────────────────────────────────────────────
    // Same NocoDB snapshot as the realistic seed so the public map keeps
    // working. We override status for the moorings we link to so the
    // dossier UI shows the expected stake levels (under_offer / sold).
    const berthRows = await tx
      .insert(berths)
      .values(
        BERTH_SNAPSHOT.map((b) => ({
          portId,
          mooringNumber: b.mooringNumber,
          area: b.area,
          status: b.status,
          lengthFt: b.lengthFt != null ? String(b.lengthFt) : null,
          widthFt: b.widthFt != null ? String(b.widthFt) : null,
          draftFt: b.draftFt != null ? String(b.draftFt) : null,
          lengthM: b.lengthM != null ? String(b.lengthM) : null,
          widthM: b.widthM != null ? String(b.widthM) : null,
          draftM: b.draftM != null ? String(b.draftM) : null,
          widthIsMinimum: b.widthIsMinimum,
          nominalBoatSize: b.nominalBoatSize != null ? String(b.nominalBoatSize) : null,
          nominalBoatSizeM: b.nominalBoatSizeM != null ? String(b.nominalBoatSizeM) : null,
          waterDepth: b.waterDepth != null ? String(b.waterDepth) : null,
          waterDepthM: b.waterDepthM != null ? String(b.waterDepthM) : null,
          waterDepthIsMinimum: b.waterDepthIsMinimum,
          sidePontoon: b.sidePontoon,
          powerCapacity: b.powerCapacity != null ? String(b.powerCapacity) : null,
          voltage: b.voltage != null ? String(b.voltage) : null,
          mooringType: b.mooringType,
          cleatType: b.cleatType,
          cleatCapacity: b.cleatCapacity,
          bollardType: b.bollardType,
          bollardCapacity: b.bollardCapacity,
          access: b.access,
          price: b.price != null ? String(b.price) : null,
          priceCurrency: 'USD',
          bowFacing: b.bowFacing,
          berthApproved: b.berthApproved,
          statusOverrideMode: b.statusOverrideMode,
          tenureType: 'permanent' as const,
        })),
      )
      .returning({ id: berths.id, status: berths.status, mooringNumber: berths.mooringNumber });

    // ── 2. Companies (one active, one with multiple memberships) ────────────
    const companyRows = await tx
      .insert(companies)
      .values([
        {
          portId,
          name: 'Test Charter Co.',
          legalName: 'Test Charter Company Ltd.',
          taxId: `TC-${portSlug}-001`,
          registrationNumber: 'TC-2024-0001',
          incorporationCountryIso: 'GB',
          incorporationDate: new Date('2024-01-01'),
          status: 'active',
          billingEmail: 'billing@testcharter.test.local',
          notes: 'Synthetic test company - has multiple member clients.',
        },
      ])
      .returning({ id: companies.id, name: companies.name });
    const charterCoId = companyRows[0]!.id;

    await tx.insert(companyAddresses).values([
      {
        companyId: charterCoId,
        portId,
        label: 'Head Office',
        streetAddress: '1 Test Street',
        city: 'London',
        subdivisionIso: null,
        postalCode: 'W1A 1AA',
        countryIso: 'GB',
        isPrimary: true,
      },
    ]);

    // ── 3. Clients ──────────────────────────────────────────────────────────
    const clientRows = await tx
      .insert(clients)
      .values(
        PIPELINE_CLIENTS.map((spec) => {
          const created =
            spec.createdDaysAgo !== undefined ? daysAgo(spec.createdDaysAgo) : new Date();
          return {
            portId,
            fullName: spec.fullName,
            nationalityIso: spec.countryIso,
            preferredContactMethod: 'email' as const,
            preferredLanguage: 'en',
            source: spec.source ?? ('manual' as const),
            // Override the schema default so the list page shows a
            // realistic range of "Created" timestamps rather than 12
            // rows all stamped with today's date. updated_at gets the
            // same value so sorted-by-recency lists put the freshest
            // records first.
            createdAt: created,
            updatedAt: created,
          };
        }),
      )
      .returning({ id: clients.id, fullName: clients.fullName });

    const idByTag = new Map<string, string>();
    PIPELINE_CLIENTS.forEach((spec, i) => idByTag.set(spec.tag, clientRows[i]!.id));

    // Contacts
    const contactValues: Array<typeof clientContacts.$inferInsert> = [];
    PIPELINE_CLIENTS.forEach((spec, i) => {
      const cid = clientRows[i]!.id;
      contactValues.push({
        clientId: cid,
        channel: 'email',
        value: spec.email,
        label: 'primary',
        isPrimary: true,
      });
      contactValues.push({
        clientId: cid,
        channel: 'phone',
        value: spec.phone,
        label: 'primary',
        isPrimary: false,
      });
    });
    await tx.insert(clientContacts).values(contactValues);

    // Addresses
    await tx.insert(clientAddresses).values(
      PIPELINE_CLIENTS.map((spec, i) => ({
        clientId: clientRows[i]!.id,
        portId,
        label: 'Primary',
        streetAddress: spec.street,
        city: spec.city,
        subdivisionIso: null,
        postalCode: spec.postalCode,
        countryIso: spec.countryIso,
        isPrimary: true,
      })),
    );

    // ── 4. Yachts (the completed-won client gets one) ───────────────────────
    const completedWonId = idByTag.get('completed-won')!;
    const charterYachtRow = await tx
      .insert(yachts)
      .values([
        {
          portId,
          name: 'Test Wanderer',
          hullNumber: 'TW-001',
          flag: 'PA',
          yearBuilt: 2018,
          builder: 'Synthetic Yard',
          model: 'Cruiser 50',
          lengthFt: '50',
          widthFt: '15',
          draftFt: '6',
          currentOwnerType: 'client' as const,
          currentOwnerId: completedWonId,
          status: 'active' as const,
          notes: 'Owned by the completed-won test client.',
        },
        {
          portId,
          name: 'Charter Co. Flagship',
          hullNumber: 'CC-FLAG-001',
          flag: 'GB',
          yearBuilt: 2022,
          builder: 'Synthetic Yard',
          model: 'Sailing Yacht 55',
          lengthFt: '55',
          widthFt: '17',
          draftFt: '7',
          currentOwnerType: 'company' as const,
          currentOwnerId: charterCoId,
          status: 'active' as const,
          notes: 'Owned by Test Charter Co.',
        },
      ])
      .returning({ id: yachts.id, name: yachts.name });

    await tx.insert(yachtOwnershipHistory).values([
      {
        yachtId: charterYachtRow[0]!.id,
        ownerType: 'client',
        ownerId: completedWonId,
        startDate: daysAgo(180),
        endDate: null,
        transferReason: null,
        transferNotes: null,
        createdBy: SUPER_ADMIN_USER_ID,
      },
      {
        yachtId: charterYachtRow[1]!.id,
        ownerType: 'company',
        ownerId: charterCoId,
        startDate: daysAgo(365),
        endDate: null,
        transferReason: null,
        transferNotes: null,
        createdBy: SUPER_ADMIN_USER_ID,
      },
    ]);

    // ── 5. Memberships (link a couple of clients to Test Charter Co.) ──────
    const dirClientId = idByTag.get('contract-sent')!;
    const officerClientId = idByTag.get('eoi-signed')!;
    await tx.insert(companyMemberships).values([
      {
        companyId: charterCoId,
        clientId: dirClientId,
        role: 'director',
        roleDetail: 'Test director',
        startDate: daysAgo(120),
        endDate: null,
        isPrimary: true,
      },
      {
        companyId: charterCoId,
        clientId: officerClientId,
        role: 'officer',
        roleDetail: 'Test officer',
        startDate: daysAgo(90),
        endDate: null,
        isPrimary: false,
      },
    ]);

    // ── 6. Berth status overrides for linked moorings ───────────────────────
    // Match the dossier classification to the berth's pipeline stage.
    // Sold = contract+signed+won. Under offer = active berth-bearing stages
    // (eoi / reservation / deposit_paid / contract-not-yet-won).
    const stageToBerthStatus = (
      spec: SyntheticClientSpec,
    ): 'available' | 'under_offer' | 'sold' | null => {
      const stage = spec.stage;
      if (!stage) return null;
      if (stage === 'contract' && spec.contractDocStatus === 'signed' && spec.outcome === 'won') {
        return 'sold';
      }
      if (
        stage === 'eoi' ||
        stage === 'reservation' ||
        stage === 'deposit_paid' ||
        stage === 'contract'
      ) {
        return 'under_offer';
      }
      return null;
    };

    for (const spec of PIPELINE_CLIENTS) {
      if (spec.berthIdx === undefined) continue;
      const newStatus = stageToBerthStatus(spec);
      if (!newStatus) continue;
      const berthId = berthRows[spec.berthIdx]!.id;
      await tx.update(berths).set({ status: newStatus }).where(eq(berths.id, berthId));
    }

    // ── 7. Interests + interest_berths ──────────────────────────────────────
    let interestCount = 0;
    for (const spec of PIPELINE_CLIENTS) {
      if (!spec.stage) continue;
      const clientId = idByTag.get(spec.tag)!;
      // Derive deal age from the (stage, doc-sub-status) pair so a
      // contract+signed+won record looks older than a brand-new enquiry.
      const stageDaysAgoMap: Record<PipelineStage, number> = {
        enquiry: 5,
        qualified: 10,
        nurturing: 30,
        eoi: spec.eoiDocStatus === 'signed' ? 35 : 20,
        reservation: 50,
        deposit_paid: 60,
        contract: spec.outcome === 'won' ? 200 : spec.contractDocStatus === 'signed' ? 110 : 80,
      };
      const ageDays = stageDaysAgoMap[spec.stage];
      const yachtId = spec.tag === 'completed-won' ? charterYachtRow[0]!.id : null;

      // Stage-progression flags so the date_* timestamps cascade correctly.
      // Anything past "eoi+sent" implies the EOI was at least sent.
      const eoiReached =
        spec.stage === 'eoi' ||
        spec.stage === 'reservation' ||
        spec.stage === 'deposit_paid' ||
        spec.stage === 'contract';
      const eoiSigned =
        (spec.stage === 'eoi' && spec.eoiDocStatus === 'signed') ||
        spec.stage === 'reservation' ||
        spec.stage === 'deposit_paid' ||
        spec.stage === 'contract';

      const [intRow] = await tx
        .insert(interests)
        .values({
          portId,
          clientId,
          yachtId,
          pipelineStage: spec.stage,
          eoiDocStatus: spec.eoiDocStatus ?? (eoiSigned ? 'signed' : null),
          reservationDocStatus: spec.reservationDocStatus ?? null,
          contractDocStatus: spec.contractDocStatus ?? null,
          leadCategory:
            spec.stage === 'enquiry'
              ? 'general_interest'
              : spec.stage === 'qualified' || spec.stage === 'nurturing'
                ? 'specific_qualified'
                : 'hot_lead',
          source: 'manual' as const,
          dateFirstContact: daysAgo(ageDays),
          dateLastContact: daysAgo(Math.max(0, ageDays - 2)),
          dateEoiSent: eoiReached ? daysAgo(Math.max(0, ageDays - 5)) : null,
          dateEoiSigned: eoiSigned ? daysAgo(Math.max(0, ageDays - 10)) : null,
          eoiStatus:
            spec.stage === 'eoi' && spec.eoiDocStatus === 'sent'
              ? 'waiting_for_signatures'
              : eoiSigned
                ? 'signed'
                : null,
          outcome: spec.outcome ?? null,
          outcomeAt: spec.outcome ? daysAgo(7) : null,
          outcomeReason:
            spec.outcome === 'lost_unqualified' ? 'Synthetic test: not qualified.' : null,
        })
        .returning({ id: interests.id });
      interestCount += 1;

      if (spec.berthIdx !== undefined) {
        const berthId = berthRows[spec.berthIdx]!.id;
        await tx.insert(interestBerths).values({
          interestId: intRow!.id,
          berthId,
          isPrimary: true,
          isSpecificInterest: true,
          isInEoiBundle: spec.stage !== 'enquiry' && spec.stage !== 'qualified',
          addedBy: SUPER_ADMIN_USER_ID,
        });
      }
    }

    // ── 8. Multi-interest client ────────────────────────────────────────────
    // Adds a second interest to "carla.comms" so the dossier shows
    // multiple deals on the same client.
    const carlaId = idByTag.get('comms')!;
    const [secondInt] = await tx
      .insert(interests)
      .values({
        portId,
        clientId: carlaId,
        yachtId: null,
        pipelineStage: 'enquiry',
        leadCategory: 'general_interest',
        source: 'website' as const,
        dateFirstContact: daysAgo(2),
        dateLastContact: daysAgo(1),
      })
      .returning({ id: interests.id });
    await tx.insert(interestBerths).values({
      interestId: secondInt!.id,
      berthId: berthRows[2]!.id,
      isPrimary: true,
      isSpecificInterest: true,
      isInEoiBundle: false,
      addedBy: SUPER_ADMIN_USER_ID,
    });

    // ── 9. Reservations ─────────────────────────────────────────────────────
    // One active reservation on the under_offer berth held by Carla,
    // one cancelled on an available berth.
    // berthTenancies requires a yacht - wire both to the charter co.
    // flagship since Carla / Olivia don't own yachts yet.
    const sharedYachtId = charterYachtRow[1]!.id;
    await tx.insert(berthTenancies).values([
      {
        portId,
        berthId: berthRows[5]!.id,
        clientId: carlaId,
        yachtId: sharedYachtId,
        startDate: daysAgo(10),
        endDate: null,
        status: 'active',
        notes: 'Synthetic active reservation.',
        createdBy: SUPER_ADMIN_USER_ID,
      },
      {
        portId,
        berthId: berthRows[3]!.id,
        clientId: idByTag.get('open')!,
        yachtId: sharedYachtId,
        startDate: daysAgo(30),
        endDate: daysAgo(20),
        status: 'cancelled',
        notes: 'Synthetic cancelled reservation.',
        createdBy: SUPER_ADMIN_USER_ID,
      },
    ]);

    // ── 10. Apply archive metadata for Anna + Rita ──────────────────────────
    const annaId = idByTag.get('archived-simple')!;
    await tx
      .update(clients)
      .set({
        archivedAt: daysAgo(30),
        // archived_by FK references the better-auth user table; the
        // synthetic super-admin is just a profile placeholder so we
        // leave this null. Field is set to the actual operator id by
        // the smart-archive service in production code paths.
        archivedBy: null,
        archiveReason: '',
        archiveMetadata: null,
      })
      .where(eq(clients.id, annaId));

    // Rich-archive: fabricate a metadata payload that the smart-restore
    // wizard will surface as auto-reversible (berth still available) +
    // opt-in-to-undo (yacht transferred).
    const ritaId = idByTag.get('archived-rich')!;
    const richMetadata: ArchiveMetadata = {
      decisions: [
        {
          kind: 'berth_released',
          refId: berthRows[2]!.id,
          detail: { mooringNumber: berthRows[2]!.mooringNumber },
        },
        {
          kind: 'yacht_transferred',
          refId: charterYachtRow[1]!.id,
          detail: { newOwnerType: 'company', newOwnerId: charterCoId },
        },
      ],
      decidedAt: daysAgo(20).toISOString(),
      decidedBy: SUPER_ADMIN_USER_ID,
      reason: 'Synthetic rich-archive for restore wizard testing.',
    };
    await tx
      .update(clients)
      .set({
        archivedAt: daysAgo(20),
        archivedBy: null,
        archiveReason: richMetadata.reason,
        archiveMetadata: richMetadata,
      })
      .where(eq(clients.id, ritaId));

    // ── 11. Residential pipeline (one per stage cluster) ────────────────────
    const residentialRows = await tx
      .insert(residentialClients)
      .values([
        {
          portId,
          fullName: 'Robert Resident',
          email: 'robert.resident@test.local',
          phone: '+1 555 020 0001',
          source: 'website' as const,
          notes: 'Synthetic residential lead.',
        },
        {
          portId,
          fullName: 'Rina Resident',
          email: 'rina.resident@test.local',
          phone: '+1 555 020 0002',
          source: 'referral' as const,
          notes: 'Synthetic residential lead - qualified.',
        },
      ])
      .returning({ id: residentialClients.id });

    await tx.insert(residentialInterests).values([
      {
        portId,
        residentialClientId: residentialRows[0]!.id,
        pipelineStage: 'new',
        notes: 'Synthetic residential interest at "new" stage.',
        dateFirstContact: daysAgo(2),
      },
      {
        portId,
        residentialClientId: residentialRows[1]!.id,
        pipelineStage: 'contacted',
        notes: 'Synthetic residential interest at "contacted" stage.',
        dateFirstContact: daysAgo(7),
        dateLastContact: daysAgo(2),
      },
    ]);

    return {
      berths: berthRows.length,
      clients: clientRows.length,
      interests: interestCount + 1, // +1 for Carla's second interest
      companies: 1,
      yachts: charterYachtRow.length,
      residentialClients: residentialRows.length,
    } satisfies SyntheticSeedSummary;
  });
}
