/**
 * Backfill `client_contacts.value_e164` from `value` for phone / whatsapp
 * contacts where it's null or empty.
 *
 * The legacy seed (and pre-normalization production data) stored phone
 * numbers in `value` as free text — "+33 4 93 00 0002" — but `value_e164`
 * is what every UI surface and dedup matcher reads. This script runs the
 * raw `value` through libphonenumber-js (via the script-safe wrapper to
 * avoid the Node 25 metadata-loader bug) and writes the canonical E.164
 * form back.
 *
 * Usage:
 *   pnpm tsx scripts/backfill-phone-e164.ts            # dry-run report
 *   pnpm tsx scripts/backfill-phone-e164.ts --apply    # actually write
 *
 * The dry-run report prints, for each unparseable row, the contact id +
 * raw value so you can hand-clean before re-running.
 */
import 'dotenv/config';
import { and, eq, inArray, isNull, or, sql } from 'drizzle-orm';

import { db } from '@/lib/db';
import { clientContacts } from '@/lib/db/schema/clients';
import { parsePhoneScriptSafe } from '@/lib/dedup/phone-parse';
import type { CountryCode } from '@/lib/i18n/countries';

const APPLY = process.argv.includes('--apply');

interface PhoneRow {
  id: string;
  channel: string;
  value: string | null;
  valueCountry: string | null;
}

async function main() {
  console.log(`Phone E.164 backfill — ${APPLY ? 'APPLY MODE' : 'dry-run'}`);
  console.log('');

  // Find candidate rows: phone or whatsapp contacts with a `value` set but
  // `value_e164` null/empty.
  const rows: PhoneRow[] = await db
    .select({
      id: clientContacts.id,
      channel: clientContacts.channel,
      value: clientContacts.value,
      valueCountry: clientContacts.valueCountry,
    })
    .from(clientContacts)
    .where(
      and(
        inArray(clientContacts.channel, ['phone', 'whatsapp']),
        or(isNull(clientContacts.valueE164), eq(clientContacts.valueE164, '')),
        sql`${clientContacts.value} IS NOT NULL AND ${clientContacts.value} <> ''`,
      ),
    );

  console.log(`  found ${rows.length} candidate rows`);

  let parsedFull = 0;
  let parsedE164Only = 0;
  let unparseable = 0;
  const updates: Array<{
    id: string;
    valueE164: string;
    valueCountry: CountryCode | null;
  }> = [];
  const fails: Array<{ id: string; value: string; reason: string }> = [];

  for (const row of rows) {
    if (!row.value) continue;
    const defaultCountry = (row.valueCountry as CountryCode | null) ?? undefined;
    const parsed1 = parsePhoneScriptSafe(row.value, defaultCountry);

    if (parsed1.e164 && parsed1.country) {
      // Both e164 + country resolved — best case.
      updates.push({ id: row.id, valueE164: parsed1.e164, valueCountry: parsed1.country });
      parsedFull++;
    } else if (parsed1.e164) {
      // E.164 came back but country didn't (e.g. UK +44 7700 900xxx
      // fictional/reserved range — libphonenumber returns the e164 form
      // but refuses to assign a country). Still safe to write — the e164
      // is canonical. Country stays null.
      updates.push({
        id: row.id,
        valueE164: parsed1.e164,
        valueCountry: (row.valueCountry as CountryCode | null) ?? null,
      });
      parsedE164Only++;
    } else {
      fails.push({
        id: row.id,
        value: row.value,
        reason: row.value.trim().startsWith('+')
          ? 'has + prefix but parse failed'
          : 'no leading + and no country hint',
      });
      unparseable++;
    }
  }

  console.log('');
  console.log('  ✓ parsed cleanly (e164 + country)', parsedFull);
  console.log('  ✓ parsed e164 only (no country) ', parsedE164Only);
  console.log('  ✗ unparseable                   ', unparseable);
  console.log('');

  if (fails.length > 0) {
    console.log('Failures (first 10):');
    for (const f of fails.slice(0, 10)) {
      console.log(`  [${f.id}] "${f.value}" — ${f.reason}`);
    }
    console.log('');
  }

  if (!APPLY) {
    console.log('Dry-run only. Re-run with --apply to write the updates.');
    return;
  }

  if (updates.length === 0) {
    console.log('No updates to write.');
    return;
  }

  console.log(`Writing ${updates.length} updates...`);

  for (const u of updates) {
    await db
      .update(clientContacts)
      .set({
        valueE164: u.valueE164,
        valueCountry: u.valueCountry,
      })
      .where(eq(clientContacts.id, u.id));
  }

  console.log(`  ✓ wrote ${updates.length} rows`);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
