import type { ApiDiscoveredProfile, ApiDiscoveredProfileGroup } from './discovery-types'
import type { FullContact } from './types'
import { FIELD_LABELS, discoveredProfileToFullContact } from './discovery-utils'
import type { ContactAddress } from './types'

export interface DraftField {
  id: string
  label: string
  fieldKey: string
  value: string
  removed: boolean
}

function fieldId(fieldKey: string, value: string) {
  return `${fieldKey}::${value}`
}

/** Clé de déduplication par valeur normalisée (indépendante du libellé / source). */
function normalizedValueKey(fieldKey: string, value: string): string {
  const v = value.trim()
  if (fieldKey === 'emails') {
    return `emails:${v.toLowerCase()}`
  }
  if (fieldKey === 'phones') {
    const digits = v.replace(/\D/g, '')
    return digits.length >= 6 ? `phones:${digits}` : `phones:${v.toLowerCase()}`
  }
  if (fieldKey === 'addresses') {
    return `addresses:${v.toLowerCase()}`
  }
  return `${fieldKey}:${v.toLowerCase()}`
}

function pushDraftField(
  out: DraftField[],
  seen: Set<string>,
  fieldKey: string,
  value: string,
  label: string,
) {
  const v = value.trim()
  if (!v) return
  const dedupeKey = normalizedValueKey(fieldKey, v)
  if (seen.has(dedupeKey)) return
  seen.add(dedupeKey)
  out.push({
    id: fieldId(fieldKey, fieldKey === 'emails' ? v.toLowerCase() : v),
    label,
    fieldKey,
    value: v,
    removed: false,
  })
}

function pushScalar(
  out: DraftField[],
  fieldKey: string,
  value: string | undefined,
  seen: Set<string>,
) {
  const v = value?.trim()
  if (!v) return
  pushDraftField(out, seen, fieldKey, v, FIELD_LABELS[fieldKey] ?? fieldKey)
}

function pushLabeled(
  out: DraftField[],
  fieldKey: string,
  items: { value: string; label?: string }[] | undefined,
  seen: Set<string>,
) {
  for (const item of items ?? []) {
    const v = item.value?.trim()
    if (!v) continue
    const suffix = item.label ? ` (${item.label})` : ''
    pushDraftField(
      out,
      seen,
      fieldKey,
      v,
      `${FIELD_LABELS[fieldKey] ?? fieldKey}${suffix}`,
    )
  }
}

export function buildDraftFields(group: ApiDiscoveredProfileGroup): DraftField[] {
  const profile = group.profile ?? group.profiles?.[0]
  if (!profile) return []

  const data = profile.enriched_data
  const seen = new Set<string>()
  const out: DraftField[] = []

  pushScalar(out, 'first_name', data?.first_name, seen)
  pushScalar(out, 'last_name', data?.last_name, seen)
  pushScalar(out, 'company', data?.company, seen)
  pushScalar(out, 'department', data?.department, seen)
  pushScalar(out, 'job_title', data?.job_title, seen)
  pushScalar(out, 'website', data?.website, seen)
  pushLabeled(out, 'social_profiles', data?.social_profiles, seen)
  pushScalar(out, 'notes', data?.notes, seen)
  pushLabeled(out, 'emails', data?.emails, seen)
  pushLabeled(out, 'phones', data?.phones, seen)

  for (const addr of data?.addresses ?? []) {
    const parts = [addr.street, addr.city, addr.region, addr.postal_code, addr.country]
      .map((p) => p?.trim())
      .filter(Boolean)
    if (parts.length === 0) continue
    const v = parts.join(', ')
    pushDraftField(
      out,
      seen,
      'addresses',
      v,
      addr.label ? `${FIELD_LABELS.addresses} (${addr.label})` : FIELD_LABELS.addresses,
    )
  }

  for (const p of group.profiles ?? [profile]) {
    for (const e of p.all_emails ?? []) {
      const v = e.email?.trim()
      if (!v) continue
      pushDraftField(out, seen, 'emails', v, FIELD_LABELS.emails)
    }
    const primary = p.primary_email?.trim()
    if (primary) {
      pushDraftField(out, seen, 'emails', primary, FIELD_LABELS.emails)
    }
  }

  return out
}

function draftFieldContactLabel(field: DraftField): string {
  const base = FIELD_LABELS[field.fieldKey] ?? field.fieldKey
  if (field.label.startsWith(base)) {
    const suffix = field.label.slice(base.length).trim()
    if (suffix.startsWith('(') && suffix.endsWith(')')) {
      return suffix.slice(1, -1)
    }
  }
  return 'Autre'
}

function parseAddressDraftValue(value: string, label: string): ContactAddress {
  const parts = value
    .split(',')
    .map((p) => p.trim())
    .filter(Boolean)
  if (parts.length >= 5) {
    return {
      street: parts[0],
      city: parts[1],
      region: parts[2],
      postalCode: parts[3],
      country: parts.slice(4).join(', '),
      label,
    }
  }
  return { street: value, label }
}

export function applyDraftToContact(
  profile: ApiDiscoveredProfile | undefined,
  fields: DraftField[],
): FullContact {
  if (!profile) {
    throw new Error('profile is required to build contact')
  }
  const base = discoveredProfileToFullContact(profile)
  const active = fields.filter((f) => !f.removed)

  const scalar = (key: string) => active.find((f) => f.fieldKey === key)?.value

  const firstName = scalar('first_name')
  const lastName = scalar('last_name')
  if (firstName) base.firstName = firstName
  if (lastName) base.lastName = lastName
  if (scalar('company')) base.company = scalar('company')
  if (scalar('department')) base.department = scalar('department')
  if (scalar('job_title')) base.jobTitle = scalar('job_title')
  if (scalar('website')) base.website = scalar('website')
  if (scalar('notes')) base.notes = scalar('notes')

  const hasSocialFields = fields.some((f) => f.fieldKey === 'social_profiles')
  const socialProfiles = active
    .filter((f) => f.fieldKey === 'social_profiles')
    .map((f) => ({
      value: f.value,
      label: draftFieldContactLabel(f),
    }))
  if (hasSocialFields) {
    base.socialProfiles = socialProfiles.length > 0 ? socialProfiles : undefined
  }

  const hasEmailFields = fields.some((f) => f.fieldKey === 'emails')
  const emails = active
    .filter((f) => f.fieldKey === 'emails')
    .map((f) => ({
      value: f.value,
      label: draftFieldContactLabel(f),
    }))
  if (hasEmailFields) base.emails = emails

  const hasPhoneFields = fields.some((f) => f.fieldKey === 'phones')
  const phones = active
    .filter((f) => f.fieldKey === 'phones')
    .map((f) => ({
      value: f.value,
      label: draftFieldContactLabel(f),
    }))
  if (hasPhoneFields) base.phones = phones

  const hasAddressFields = fields.some((f) => f.fieldKey === 'addresses')
  const addresses = active
    .filter((f) => f.fieldKey === 'addresses')
    .map((f) => parseAddressDraftValue(f.value, draftFieldContactLabel(f)))
  if (hasAddressFields) {
    base.addresses = addresses.length > 0 ? addresses : undefined
  }

  return base
}
