import Link from 'next/link'
import { createClient } from '@/lib/supabase/server'
import { getAppOrg } from '@/lib/org'
import { getEffectiveUser } from '@/lib/effective-user'
import { canManageImports, canTransfer } from '@/lib/permissions'
import type { ParsedEntry } from '@/lib/clockify'
import { ResolverForm } from './resolver-form'

type PendingRow = {
  id: string
  org_id: string
  uploaded_by: string
  filename: string | null
  batch_name: string | null
  source: 'clockify' | 'toggl'
  parsed_entries: ParsedEntry[]
}

type Operator = { id: string; name: string }
type Client = { id: string; operator_id: string; name: string }
type Project = { id: string; client_id: string; name: string }

export default async function ResolveImportPage({
  searchParams,
}: {
  searchParams: Promise<{ id?: string; error?: string }>
}) {
  const { id, error } = await searchParams

  if (!id) {
    return (
      <main>
        <div className="page-head">
          <h1>Resolve import</h1>
        </div>
        <p className="error">Missing pending-import id.</p>
        <p>
          <Link href="/import">← Back to import</Link>
        </p>
      </main>
    )
  }

  const supabase = await createClient()
  const org = await getAppOrg(supabase)
  if (!org) {
    return (
      <main>
        <p className="error">Org not found.</p>
      </main>
    )
  }

  // RLS-gated. Manager sees their own; owner sees all.
  const eu = await getEffectiveUser(supabase, org.id)

  const { data: pending } = await supabase
    .from('pending_imports')
    .select('id, org_id, uploaded_by, filename, batch_name, source, parsed_entries')
    .eq('id', id)
    .maybeSingle<PendingRow>()

  if (!pending) {
    return (
      <main>
        <div className="page-head">
          <h1>Resolve import</h1>
        </div>
        <p className="error">
          Pending import not found. It may have expired (they last 24h)
          or someone else cancelled it.
        </p>
        <p>
          <Link href="/import">← Back to import</Link>
        </p>
      </main>
    )
  }

  const parsed = pending.parsed_entries ?? []

  // Existing entities for cross-reference and the "map to existing" dropdowns.
  const { data: operators } = await supabase
    .from('operators')
    .select('id, name')
    .eq('org_id', org.id)
    .order('name')
    .returns<Operator[]>()
  const { data: clients } = await supabase
    .from('clients')
    .select('id, operator_id, name')
    .eq('org_id', org.id)
    .order('name')
    .returns<Client[]>()
  const { data: projects } = await supabase
    .from('projects')
    .select('id, client_id, name')
    .eq('org_id', org.id)
    .order('name')
    .returns<Project[]>()

  const opLowerToId = new Map(
    (operators ?? []).map((o) => [o.name.toLowerCase(), o.id]),
  )
  const clLowerToId = new Map(
    (clients ?? []).map((c) => [`${c.operator_id}|${c.name.toLowerCase()}`, c.id]),
  )
  const prLowerToId = new Map(
    (projects ?? []).map((p) => [`${p.client_id}|${p.name.toLowerCase()}`, p.id]),
  )

  // Extract distinct names from the CSV.
  const distinctOperators = Array.from(
    new Set(parsed.map((e) => e.operator).filter((o): o is string => !!o)),
  ).sort()
  const distinctOpClients = Array.from(
    new Set(
      parsed
        .filter((e) => e.operator && e.client)
        .map((e) => `${e.operator}|${e.client}`),
    ),
  ).sort()
  const distinctTriples = Array.from(
    new Set(
      parsed
        .filter((e) => e.operator && e.client && e.project)
        .map((e) => `${e.operator}|${e.client}|${e.project}`),
    ),
  ).sort()

  // For each distinct name, mark known or unknown.
  const operatorRows = distinctOperators.map((name) => ({
    name,
    existingId: opLowerToId.get(name.toLowerCase()) ?? null,
  }))

  type OpClientRow = {
    opName: string
    clName: string
    /** The operator entity id IF the operator name resolves, OR — when it
     * doesn't — null so the UI can label "depends on operator decision". */
    operatorEntityId: string | null
    existingId: string | null
  }
  const clientRows: OpClientRow[] = distinctOpClients.map((key) => {
    const [opName, clName] = key.split('|', 2)
    const opId = opLowerToId.get(opName.toLowerCase()) ?? null
    const clId = opId
      ? clLowerToId.get(`${opId}|${clName.toLowerCase()}`) ?? null
      : null
    return {
      opName,
      clName,
      operatorEntityId: opId,
      existingId: clId,
    }
  })

  type ProjectRow = {
    opName: string
    clName: string
    prName: string
    clientEntityId: string | null
    existingId: string | null
  }
  const projectRows: ProjectRow[] = distinctTriples.map((key) => {
    const [opName, clName, prName] = key.split('|', 3)
    const opId = opLowerToId.get(opName.toLowerCase()) ?? null
    const clId = opId
      ? clLowerToId.get(`${opId}|${clName.toLowerCase()}`) ?? null
      : null
    const prId = clId
      ? prLowerToId.get(`${clId}|${prName.toLowerCase()}`) ?? null
      : null
    return {
      opName,
      clName,
      prName,
      clientEntityId: clId,
      existingId: prId,
    }
  })

  // Summary counts.
  const knownOps = operatorRows.filter((r) => r.existingId).length
  const unknownOps = operatorRows.length - knownOps
  const knownCls = clientRows.filter((r) => r.existingId).length
  const unknownCls = clientRows.length - knownCls
  const knownPrs = projectRows.filter((r) => r.existingId).length
  const unknownPrs = projectRows.length - knownPrs

  const allKnown = unknownOps === 0 && unknownCls === 0 && unknownPrs === 0
  // canSubmit: must have import-management permission AND either own
  // this pending OR be an owner-equivalent (who can resolve anyone's).
  // Uploads are attributed to `effective_user_id` (ADR #033 — view-as
  // is true impersonation), so we compare to that, not real_user_id.
  // canTransfer covers both real owners and super admins not in
  // view-as; canManageImports covers managers (Adi) too — they
  // SHOULD be the primary importers.
  const canSubmit =
    canManageImports(eu) &&
    (pending.uploaded_by === eu?.effective_user_id || canTransfer(eu))

  return (
    <main>
      <div className="page-head">
        <div>
          <h1>Resolve import</h1>
          <p className="subtitle">
            {pending.batch_name ? <strong>{pending.batch_name}</strong> : 'Unnamed batch'} ·{' '}
            {pending.filename ?? '(no filename)'} · {pending.source} ·{' '}
            <strong>{parsed.length}</strong> entries
          </p>
        </div>
        <div className="page-head-actions">
          <Link href="/import" className="button-link-secondary">
            ← Cancel and go back
          </Link>
        </div>
      </div>

      {error && <p className="error">{error}</p>}

      <div className="panel">
        <div
          style={{ display: 'flex', gap: '2rem', alignItems: 'center', flexWrap: 'wrap' }}
        >
          <Stat label="Operators" known={knownOps} unknown={unknownOps} />
          <Stat label="Clients" known={knownCls} unknown={unknownCls} />
          <Stat label="Projects" known={knownPrs} unknown={unknownPrs} />
        </div>
        {allKnown ? (
          <p className="info" style={{ marginTop: '0.5rem' }}>
            ✓ All names already exist. Click <strong>Import</strong> below to
            commit {parsed.length} entries.
          </p>
        ) : (
          <p className="warning" style={{ marginTop: '0.5rem' }}>
            Some names in this CSV don&apos;t match existing entities. Pick
            <strong> Create new</strong> or <strong>Map to existing</strong> for
            each, then click <strong>Import</strong> to commit.
          </p>
        )}
      </div>

      {!canSubmit ? (
        <p className="error">
          You don&apos;t have permission to commit this import.
        </p>
      ) : (
        <ResolverForm
          pendingId={pending.id}
          operatorRows={operatorRows}
          clientRows={clientRows}
          projectRows={projectRows}
          operators={operators ?? []}
          clients={clients ?? []}
          projects={projects ?? []}
        />
      )}
    </main>
  )
}

function Stat({
  label,
  known,
  unknown,
}: {
  label: string
  known: number
  unknown: number
}) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '0.15rem' }}>
      <span className="muted" style={{ fontSize: '0.85em' }}>
        {label}
      </span>
      <span style={{ fontSize: '0.95em' }}>
        <strong>{known}</strong> known
        {unknown > 0 && (
          <span
            className="under-target"
            style={{ marginLeft: '0.5rem', fontWeight: 600 }}
          >
            · {unknown} unknown
          </span>
        )}
      </span>
    </div>
  )
}
