'use client'

import { useMemo, useState } from 'react'
import { commitPendingImport, cancelPendingImport } from './actions'

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

type OperatorRow = { name: string; existingId: string | null }
type ClientRow = {
  opName: string
  clName: string
  /** operator entity id if the op resolved by name */
  operatorEntityId: string | null
  existingId: string | null
}
type ProjectRow = {
  opName: string
  clName: string
  prName: string
  clientEntityId: string | null
  existingId: string | null
}

type Props = {
  pendingId: string
  operatorRows: OperatorRow[]
  clientRows: ClientRow[]
  projectRows: ProjectRow[]
  operators: Operator[]
  clients: Client[]
  projects: Project[]
}

/** Decision value encoded in a single form field. */
type Decision = 'create' | string // `create` or `map:<uuid>`

/**
 * Form layout: one row per UNKNOWN name in each section. Each row has
 * two radios (Create new / Map to existing) and, for the latter, a
 * dropdown of candidate entities. Known names render as a static "✓
 * known" line for transparency, no input needed.
 */
export function ResolverForm({
  pendingId,
  operatorRows,
  clientRows,
  projectRows,
  operators,
  clients,
  projects,
}: Props) {
  // Initial decisions: Create new for every unknown. Once any name is
  // mapped to an existing entity, we remember that and the next time we
  // see the same name elsewhere we can pre-fill its dropdown.
  const initialOpDecisions: Record<number, Decision> = {}
  operatorRows.forEach((r, i) => {
    if (!r.existingId) initialOpDecisions[i] = 'create'
  })
  const initialClDecisions: Record<number, Decision> = {}
  clientRows.forEach((r, i) => {
    if (!r.existingId) initialClDecisions[i] = 'create'
  })
  const initialPrDecisions: Record<number, Decision> = {}
  projectRows.forEach((r, i) => {
    if (!r.existingId) initialPrDecisions[i] = 'create'
  })

  const [opDec, setOpDec] = useState(initialOpDecisions)
  const [clDec, setClDec] = useState(initialClDecisions)
  const [prDec, setPrDec] = useState(initialPrDecisions)

  // Helpers to pre-build candidate dropdowns at the right scope.
  // For clients: candidates are clients under the (already-resolved or
  // about-to-be-created) operator. For now, we filter on the existing
  // operatorEntityId — if the operator is being created, there are no
  // existing client candidates to map to anyway, so the radio defaults
  // to Create new and the dropdown is empty.
  function clientCandidates(opEntityId: string | null): Client[] {
    if (!opEntityId) return []
    return clients.filter((c) => c.operator_id === opEntityId)
  }
  function projectCandidates(clientEntityId: string | null): Project[] {
    if (!clientEntityId) return []
    return projects.filter((p) => p.client_id === clientEntityId)
  }

  // Effective client_id for a given (opName, clName), accounting for
  // the user's current decisions. If the row already resolved at
  // server-render time, use the stored id. If the user mapped it to
  // an existing client via the dropdown, use the mapped target. If
  // they picked Create new (or the row is genuinely new), return
  // null — projects under it have no candidates to choose from.
  //
  // Computed via useMemo so the project pickers re-render reactively
  // whenever clDec flips.
  const effectiveClientId = useMemo(() => {
    const map = new Map<string, string>()
    clientRows.forEach((r, i) => {
      const key = `${r.opName}|${r.clName}`
      if (r.existingId) {
        map.set(key, r.existingId)
        return
      }
      const dec = clDec[i]
      if (dec && dec.startsWith('map:')) {
        map.set(key, dec.slice(4))
      }
    })
    return map
  }, [clientRows, clDec])

  const hasUnknowns =
    operatorRows.some((r) => !r.existingId) ||
    clientRows.some((r) => !r.existingId) ||
    projectRows.some((r) => !r.existingId)

  return (
    <form action={commitPendingImport}>
      <input type="hidden" name="pending_id" value={pendingId} />

      <Section
        title="Operators"
        emptyMessage="No operator names in this CSV."
      >
        {operatorRows.length === 0 ? null : (
          <ul style={listStyle}>
            {operatorRows.map((r, i) => (
              <li key={`op-${i}`} style={rowStyle}>
                {r.existingId ? (
                  <KnownLine label={r.name} />
                ) : (
                  <UnknownRow
                    name={r.name}
                    candidates={operators}
                    decision={opDec[i] ?? 'create'}
                    onChange={(v) => setOpDec({ ...opDec, [i]: v })}
                    inputName={`op_decision_${i}`}
                    nameField={
                      <input
                        type="hidden"
                        name={`op_name_${i}`}
                        value={r.name}
                      />
                    }
                  />
                )}
              </li>
            ))}
          </ul>
        )}
      </Section>

      <Section
        title="Clients"
        emptyMessage="No client names in this CSV."
      >
        {clientRows.length === 0 ? null : (
          <ul style={listStyle}>
            {clientRows.map((r, i) => (
              <li key={`cl-${i}`} style={rowStyle}>
                {r.existingId ? (
                  <KnownLine label={`${r.opName} / ${r.clName}`} />
                ) : (
                  <UnknownRow
                    name={r.clName}
                    contextLabel={
                      <>
                        under <em>{r.opName}</em>
                        {!r.operatorEntityId && (
                          <span className="muted">
                            {' '}(new operator — will be created)
                          </span>
                        )}
                      </>
                    }
                    candidates={clientCandidates(r.operatorEntityId)}
                    decision={clDec[i] ?? 'create'}
                    onChange={(v) => setClDec({ ...clDec, [i]: v })}
                    inputName={`cl_decision_${i}`}
                    nameField={
                      <input
                        type="hidden"
                        name={`cl_name_${i}`}
                        value={`${r.opName}|${r.clName}`}
                      />
                    }
                  />
                )}
              </li>
            ))}
          </ul>
        )}
      </Section>

      <Section
        title="Projects"
        emptyMessage="No project names in this CSV."
      >
        {projectRows.length === 0 ? null : (
          <ul style={listStyle}>
            {projectRows.map((r, i) => {
              // Use the user's current client decision to scope the
              // project candidates. r.clientEntityId is the
              // server-render-time fact; effectiveClientId merges in
              // the user's in-flight mapping decisions.
              const effClientId =
                r.clientEntityId ??
                effectiveClientId.get(`${r.opName}|${r.clName}`) ??
                null
              const clientLooksKnown = effClientId != null
              return (
                <li key={`pr-${i}`} style={rowStyle}>
                  {r.existingId ? (
                    <KnownLine
                      label={`${r.opName} / ${r.clName} / ${r.prName}`}
                    />
                  ) : (
                    <UnknownRow
                      name={r.prName}
                      contextLabel={
                        <>
                          under <em>{r.opName}</em> /{' '}
                          <em>{r.clName}</em>
                          {!clientLooksKnown && (
                            <span className="muted">
                              {' '}(new client — will be created)
                            </span>
                          )}
                        </>
                      }
                      candidates={projectCandidates(effClientId)}
                      decision={prDec[i] ?? 'create'}
                      onChange={(v) => setPrDec({ ...prDec, [i]: v })}
                      inputName={`pr_decision_${i}`}
                      nameField={
                        <input
                          type="hidden"
                          name={`pr_name_${i}`}
                          value={`${r.opName}|${r.clName}|${r.prName}`}
                        />
                      }
                    />
                  )}
                </li>
              )
            })}
          </ul>
        )}
      </Section>

      <div className="panel" style={{ display: 'flex', gap: '0.75rem', alignItems: 'center', flexWrap: 'wrap' }}>
        <button type="submit">
          {hasUnknowns ? 'Apply decisions and import' : 'Import'}
        </button>
        <button
          type="submit"
          formAction={cancelPendingImport}
          className="secondary"
        >
          Cancel
        </button>
        <span className="muted" style={{ fontSize: '0.85em' }}>
          New entities will be created with the names as they appear in the CSV.
          You can rename them later from <a href="/projects/manage">Manage entities</a>.
        </span>
      </div>
    </form>
  )
}

const listStyle: React.CSSProperties = {
  listStyle: 'none',
  padding: 0,
  margin: 0,
}
const rowStyle: React.CSSProperties = {
  padding: '0.5rem 0',
  borderBottom: '1px solid #f0f0f0',
}

function Section({
  title,
  children,
  emptyMessage,
}: {
  title: string
  children: React.ReactNode
  emptyMessage: string
}) {
  return (
    <div className="panel" style={{ padding: 0, overflow: 'hidden' }}>
      <div style={{ padding: '0.75rem 1rem 0.5rem' }}>
        <h2 style={{ margin: 0, fontSize: '1.05rem' }}>{title}</h2>
      </div>
      <div style={{ padding: '0 1rem 0.75rem' }}>
        {children ?? <p className="muted">{emptyMessage}</p>}
      </div>
    </div>
  )
}

function KnownLine({ label }: { label: string }) {
  return (
    <div style={{ color: '#0a7d3f' }}>
      ✓ <strong>{label}</strong>{' '}
      <span className="muted" style={{ fontSize: '0.85em' }}>
        — already exists
      </span>
    </div>
  )
}

function UnknownRow({
  name,
  contextLabel,
  candidates,
  decision,
  onChange,
  inputName,
  nameField,
}: {
  name: string
  contextLabel?: React.ReactNode
  candidates: { id: string; name: string }[]
  decision: Decision
  onChange: (v: Decision) => void
  inputName: string
  nameField: React.ReactNode
}) {
  const isMap = decision.startsWith('map:')

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '0.35rem' }}>
      <div>
        <strong>{name}</strong>
        {contextLabel && (
          <span
            className="muted"
            style={{ marginLeft: '0.5rem', fontSize: '0.9em' }}
          >
            {contextLabel}
          </span>
        )}
      </div>
      {nameField}
      <div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem', paddingLeft: '1rem' }}>
        <label style={{ display: 'inline-flex', gap: '0.4rem', alignItems: 'center' }}>
          <input
            type="radio"
            name={inputName}
            value="create"
            checked={!isMap}
            onChange={() => onChange('create')}
          />
          Create new <code style={{ fontSize: '0.85em' }}>“{name}”</code>
        </label>
        <label
          style={{
            display: 'inline-flex',
            gap: '0.4rem',
            alignItems: 'center',
            opacity: candidates.length === 0 ? 0.5 : 1,
          }}
        >
          <input
            type="radio"
            name={inputName}
            value={isMap ? decision : 'map:'}
            checked={isMap}
            onChange={() => {
              const first = candidates[0]
              if (first) onChange(`map:${first.id}`)
            }}
            disabled={candidates.length === 0}
          />
          Map to existing:{' '}
          <select
            value={isMap ? decision.slice(4) : ''}
            onChange={(e) => {
              if (e.target.value) onChange(`map:${e.target.value}`)
            }}
            disabled={candidates.length === 0 || !isMap}
            style={{ minWidth: '14rem' }}
          >
            {candidates.length === 0 && (
              <option value="">(no candidates at this scope)</option>
            )}
            {candidates.map((c) => (
              <option key={c.id} value={c.id}>
                {c.name}
              </option>
            ))}
          </select>
        </label>
      </div>
    </div>
  )
}
