"use client"

// Massimport av spillere via CSV (2026-08-17, ADR-082). Denne filen er
// ORKESTRERINGSLAGET (CSV-parsing, kolonnegjetting, lagre-orkestrering
// mot ekte API-endepunkter) -- selve VISNINGEN er V0-eksportert
// (player-import-view.tsx, "stor skjerm først"-prompt), en ren
// kontrollert komponent uten egne API-kall. Speiler FlagPlantSheet-
// mønsteret: Claude skriver/eier logikken, V0 eier presentasjonen.

import { useState } from "react"
import Papa from "papaparse"
import { TriangleAlert } from "lucide-react"
import {
  PlayerImportView,
  type DraftRow,
  type FieldKey,
  type Mode,
} from "@/components/player-import-view"

const EMPTY_ROW: Omit<DraftRow, "key"> = {
  display_name: "",
  email: "",
  handicap_index: "",
  gender: "",
  birth_date: "",
  mobile: "",
  club: "",
  nickname: "",
  country: "",
  club_member_number: "",
  first_name: "",
  last_name: "",
  comment: "",
  team_name: "",
  class_name: "",
}

// Fuzzy gjetting av kolonnetilknytning -- små bokstaver, uten mellomrom/
// bindestrek/norske spesialtegn, sammenlignet mot vanlige norske/
// engelske varianter. Diakritisk normalisering (æøå -- fikset 2026-08-17,
// se ADR-082 sin "kjent begrensning"-note) lar f.eks. "Kjønn" treffe
// "kjonn" i tabellen under uten at brukeren må skrive om headeren.
const HEADER_GUESSES: Record<string, FieldKey> = {
  navn: "display_name",
  name: "display_name",
  fulltnavn: "display_name",
  spillernavn: "display_name",
  epost: "email",
  email: "email",
  mail: "email",
  hcp: "handicap_index",
  handicap: "handicap_index",
  spillehandicap: "handicap_index",
  kjonn: "gender",
  gender: "gender",
  fodselsdato: "birth_date",
  fodtdato: "birth_date",
  birthdate: "birth_date",
  fodt: "birth_date",
  mobil: "mobile",
  mobile: "mobile",
  telefon: "mobile",
  phone: "mobile",
  klubb: "club",
  club: "club",
  medlemsnr: "club_member_number",
  medlemsnummer: "club_member_number",
  fornavn: "first_name",
  firstname: "first_name",
  etternavn: "last_name",
  lastname: "last_name",
  lag: "team_name",
  lagnavn: "team_name",
  team: "team_name",
  klasse: "class_name",
  class: "class_name",
  kommentar: "comment",
  comment: "comment",
  land: "country",
  country: "country",
  kallenavn: "nickname",
  nickname: "nickname",
}

function normalizeHeader(h: string): string {
  return h
    .trim()
    .toLowerCase()
    .replace(/[æä]/g, "a")
    .replace(/[øö]/g, "o")
    .replace(/å/g, "a")
    .replace(/[\s_-]+/g, "")
}

function guessField(header: string): FieldKey | "" {
  return HEADER_GUESSES[normalizeHeader(header)] ?? ""
}

// V0-visningens Kjønn-nedtrekk forventer nøyaktig "female"/"male"/"other"
// (se player-import-view.tsx GENDER_OPTIONS) -- rå CSV-tekst ("m"/"f"/
// "Mann"/"Kvinne"/osv.) normaliseres til det vokabularet HER, ved selve
// kolonnetilknytningen, IKKE bare kopiert inn rått. Ukjent verdi -> ""
// (vises som "—", brukeren kan velge manuelt -- ikke tapt data siden det
// bare skjer ved selve mappingen, aldri ved lagring).
const GENDER_VALUE_GUESSES: Record<string, string> = {
  m: "male",
  mann: "male",
  male: "male",
  herre: "male",
  h: "male",
  f: "female",
  female: "female",
  kvinne: "female",
  dame: "female",
  k: "female",
  x: "other",
  annet: "other",
  other: "other",
}

function guessGenderValue(raw: string): string {
  return GENDER_VALUE_GUESSES[raw.trim().toLowerCase()] ?? ""
}

// V0s visning bruker lesbare engelske verdier for kjønn-nedtrekket
// (female/male/other) -- backend (app/routers/players.py) forventer
// PlayerCreate.gender = ett tegn (^[mfx]$). Oversettes her, i
// orkestreringslaget, IKKE ved å endre V0-visningen.
function toBackendGender(value: string): string | null {
  if (value === "female") return "f"
  if (value === "male") return "m"
  if (value === "other") return "x"
  return null
}

type ApiPlayer = {
  id: string
  display_name: string
  handicap_index: number | null
  gender: string | null
  mobile: string | null
  email: string | null
  birth_date: string | null
  nickname: string | null
  country: string | null
  club: string | null
  club_member_number: string | null
  first_name: string | null
  last_name: string | null
  paid: boolean
  comment: string | null
}

type DuplicateAction = "merge" | "overwrite" | "create_new"

// Mulig duplikat (2026-08-18, ekte produksjonsbug): en importrad UTEN
// e-post har ingen pålitelig matchingsnøkkel i seg selv (se players.py
// sin create_players_bulk-docstring for hele historikken), så et
// navnetreff mot en spiller som allerede finnes i poolen blir aldri
// slått sammen automatisk -- for risikabelt, to ulike ekte personer kan
// dele navn. Organisator spørres eksplisitt i stedet, se DuplicateStep.
type DuplicateCandidate = {
  row: DraftRow
  existing: ApiPlayer
  action: DuplicateAction
}

export function PlayerImportPanel({
  organizationId,
  tournamentId,
  mode,
  onClose,
  onImportComplete,
}: {
  organizationId: string
  tournamentId: string
  mode: Mode
  onClose: () => void
  onImportComplete: (createdOrUpdated: { player: ApiPlayer; status: string }[]) => void
}) {
  const [step, setStep] = useState<"upload" | "map" | "edit" | "duplicates" | "saving" | "done">("upload")
  const [csvHeaders, setCsvHeaders] = useState<string[]>([])
  const [csvRows, setCsvRows] = useState<string[][]>([])
  const [mapping, setMapping] = useState<Record<number, FieldKey | "">>({})
  const [rows, setRows] = useState<DraftRow[]>([])
  const [error, setError] = useState<string | null>(null)
  const [saveWarnings, setSaveWarnings] = useState<string[]>([])
  const [duplicates, setDuplicates] = useState<DuplicateCandidate[]>([])

  function handleFile(file: File) {
    setError(null)
    Papa.parse<string[]>(file, {
      skipEmptyLines: true,
      complete: (result) => {
        const data = result.data
        if (data.length === 0) {
          setError("Fant ingen rader i filen.")
          return
        }
        const headers = data[0]
        const body = data.slice(1)
        setCsvHeaders(headers)
        setCsvRows(body)
        const guessed: Record<number, FieldKey | ""> = {}
        headers.forEach((h, i) => {
          guessed[i] = guessField(h)
        })
        setMapping(guessed)
        setStep("map")
      },
      error: () => setError("Klarte ikke å lese filen. Er det en gyldig CSV?"),
    })
  }

  function confirmMapping() {
    const mapped: DraftRow[] = csvRows.map((cells, i) => {
      const row: DraftRow = { key: `csv-${i}`, ...EMPTY_ROW }
      csvHeaders.forEach((_, colIdx) => {
        const field = mapping[colIdx]
        if (!field) return
        const raw = (cells[colIdx] ?? "").trim()
        row[field] = field === "gender" ? guessGenderValue(raw) : raw
      })
      return row
    })
    setRows(mapped)
    setStep("edit")
  }

  function updateCell(key: string, field: FieldKey, value: string) {
    setRows((prev) => prev.map((r) => (r.key === key ? { ...r, [field]: value } : r)))
  }

  function addBlankRow() {
    setRows((prev) => [...prev, { key: `manual-${Date.now()}`, ...EMPTY_ROW }])
  }

  function removeRow(key: string) {
    setRows((prev) => prev.filter((r) => r.key !== key))
  }

  function teamIdForName(name: string): string | null {
    if (mode.kind !== "team") return null
    const match = mode.teams.find((t) => t.name.trim().toLowerCase() === name.trim().toLowerCase())
    return match?.id ?? null
  }

  function classIdForName(name: string): string | null {
    if (mode.kind !== "individual") return null
    const match = mode.classes.find((c) => c.name.trim().toLowerCase() === name.trim().toLowerCase())
    return match?.id ?? null
  }

  // Trykk på "Lagre" i redigeringstabellen -- sjekker FØRST om noen av
  // radene ser ut som mulige duplikater (ingen e-post + navnetreff mot en
  // spiller som allerede finnes i poolen). Finnes det slike, stopper vi
  // her og spør organisator eksplisitt (DuplicateStep) i stedet for å
  // stille velge -- se DuplicateCandidate-kommentaren over. Ellers går vi
  // rett til doSave().
  async function handleSave() {
    const validRows = rows.filter((r) => r.display_name.trim().length > 0)
    if (validRows.length === 0) {
      setError("Ingen rader med navn å lagre.")
      return
    }
    setError(null)

    const noEmailRows = validRows.filter((r) => !r.email.trim())
    if (noEmailRows.length > 0) {
      const existingRes = await fetch(`/orgs/${organizationId}/players`, { credentials: "include" })
      if (existingRes.ok) {
        const existingPlayers: ApiPlayer[] = await existingRes.json()
        const byName = new Map<string, ApiPlayer>()
        for (const p of existingPlayers) byName.set(p.display_name.trim().toLowerCase(), p)
        const candidates: DuplicateCandidate[] = noEmailRows
          .map((row) => {
            const existing = byName.get(row.display_name.trim().toLowerCase())
            return existing ? { row, existing, action: "merge" as DuplicateAction } : null
          })
          .filter((c): c is DuplicateCandidate => c !== null)
        if (candidates.length > 0) {
          setDuplicates(candidates)
          setStep("duplicates")
          return
        }
      }
    }
    await doSave(validRows, [])
  }

  async function doSave(validRows: DraftRow[], resolvedDuplicates: DuplicateCandidate[]) {
    setStep("saving")
    setSaveWarnings([])
    try {
      const resolutionByRowKey = new Map(resolvedDuplicates.map((d) => [d.row.key, d]))
      const payload = validRows.map((r) => {
        const resolution = resolutionByRowKey.get(r.key)
        return {
          data: {
            display_name: r.display_name.trim(),
            email: r.email.trim() || null,
            handicap_index: r.handicap_index.trim() ? Number(r.handicap_index) : null,
            gender: toBackendGender(r.gender),
            birth_date: r.birth_date.trim() || null,
            mobile: r.mobile.trim() || null,
            club: r.club.trim() || null,
            nickname: r.nickname.trim() || null,
            country: r.country.trim() || null,
            club_member_number: r.club_member_number.trim() || null,
            first_name: r.first_name.trim() || null,
            last_name: r.last_name.trim() || null,
            comment: r.comment.trim() || null,
          },
          match_player_id: resolution && resolution.action !== "create_new" ? resolution.existing.id : null,
          duplicate_action: resolution?.action ?? null,
        }
      })
      const bulkRes = await fetch(`/orgs/${organizationId}/players/bulk`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        credentials: "include",
        body: JSON.stringify(payload),
      })
      if (!bulkRes.ok) throw new Error(`bulk: ${bulkRes.status}`)
      const results: { player: ApiPlayer; status: string }[] = await bulkRes.json()

      const warnings: string[] = []
      for (let i = 0; i < validRows.length; i++) {
        const row = validRows[i]
        const player = results[i]?.player
        if (!player) continue
        if (mode.kind === "team") {
          const teamId = teamIdForName(row.team_name)
          if (!teamId) {
            if (row.team_name.trim()) {
              warnings.push(`${row.display_name}: fant ikke laget "${row.team_name}" -- lagt i spillerpoolen, ikke på lag.`)
            }
            continue
          }
          const res = await fetch(`/orgs/${organizationId}/teams/${teamId}/roster`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            credentials: "include",
            body: JSON.stringify({ player_id: player.id }),
          })
          if (!res.ok && res.status !== 409) {
            warnings.push(`${row.display_name}: klarte ikke å legge til på laget.`)
          }
        } else {
          const classId = row.class_name.trim() ? classIdForName(row.class_name) : null
          const res = await fetch(`/orgs/${organizationId}/tournaments/${tournamentId}/participants`, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            credentials: "include",
            body: JSON.stringify({ player_id: player.id, class_id: classId }),
          })
          if (!res.ok && res.status !== 409) {
            warnings.push(`${row.display_name}: klarte ikke å melde på turneringen.`)
          }
        }
      }
      setSaveWarnings(warnings)
      setStep("done")
      onImportComplete(results)
    } catch {
      setError("Importen feilet. Prøv igjen.")
      setStep("edit")
    }
  }

  if (step === "duplicates") {
    return (
      <DuplicateStep
        duplicates={duplicates}
        onChangeAction={(rowKey, action) =>
          setDuplicates((prev) => prev.map((d) => (d.row.key === rowKey ? { ...d, action } : d)))
        }
        onCancel={() => setStep("edit")}
        onContinue={() => void doSave(rows.filter((r) => r.display_name.trim().length > 0), duplicates)}
      />
    )
  }

  return (
    <PlayerImportView
      mode={mode}
      step={step}
      csvHeaders={csvHeaders}
      columnMapping={mapping}
      rows={rows}
      errorMessage={error}
      saveWarnings={saveWarnings}
      onFileSelected={handleFile}
      onColumnMappingChange={(colIdx, field) => setMapping((prev) => ({ ...prev, [colIdx]: field }))}
      onConfirmMapping={confirmMapping}
      onCellChange={updateCell}
      onDeleteRow={removeRow}
      onAddBlankRow={addBlankRow}
      onSave={() => void handleSave()}
      onClose={onClose}
    />
  )
}

// Duplikat-varsel (2026-08-18, se DuplicateCandidate-kommentaren over) --
// funksjonell, håndkodet av Claude (ikke V0-eksportert som resten av
// import-visningen): en liten, avgrenset spørre-skjerm satt inn FØR selve
// lagringen, ikke en ny selvstendig UI-flate. Bruker de samme globale
// design-tokenene (border/bg-card/bg-primary osv.) som resten av appen.
function DuplicateStep({
  duplicates,
  onChangeAction,
  onCancel,
  onContinue,
}: {
  duplicates: DuplicateCandidate[]
  onChangeAction: (rowKey: string, action: DuplicateAction) => void
  onCancel: () => void
  onContinue: () => void
}) {
  const ACTIONS: { value: DuplicateAction; label: string; hint: string }[] = [
    { value: "merge", label: "Slå sammen", hint: "Fyll kun inn tomme felt på den eksisterende spilleren" },
    { value: "overwrite", label: "Overskriv", hint: "Erstatt ALLE felt på den eksisterende spilleren" },
    { value: "create_new", label: "Importer som ny", hint: "Behold begge -- bevisst dobbeloppføring" },
  ]

  return (
    <div className="mx-auto flex w-full max-w-3xl flex-col gap-6 p-4 sm:p-6">
      <div className="flex items-start gap-3 rounded-xl border border-border bg-card p-4 sm:p-5">
        <TriangleAlert aria-hidden="true" className="mt-0.5 size-6 shrink-0 text-amber-600 dark:text-amber-400" />
        <div className="flex flex-col gap-1">
          <h2 className="text-lg font-bold text-foreground">
            {duplicates.length === 1 ? "1 mulig duplikat funnet" : `${duplicates.length} mulige duplikater funnet`}
          </h2>
          <p className="text-sm font-medium text-muted-foreground text-pretty">
            Disse radene mangler e-post og har samme navn som en spiller som allerede finnes i
            spillerpoolen. Velg hva som skal skje med hver av dem før import fortsetter.
          </p>
        </div>
      </div>

      <ul className="flex flex-col gap-4">
        {duplicates.map((d) => (
          <li key={d.row.key} className="rounded-xl border border-border bg-card p-4 sm:p-5">
            <p className="text-base font-bold text-foreground">{d.row.display_name.trim()}</p>
            <p className="text-sm font-medium text-muted-foreground">
              Finnes allerede i spillerpoolen
              {d.existing.club ? ` -- ${d.existing.club}` : ""}
              {d.existing.handicap_index != null ? `, HCP ${d.existing.handicap_index}` : ""}
            </p>
            <fieldset className="mt-3 flex flex-col gap-2 sm:flex-row sm:flex-wrap">
              <legend className="sr-only">Hva skal skje med {d.row.display_name.trim()}?</legend>
              {ACTIONS.map((a) => {
                const id = `dup-${d.row.key}-${a.value}`
                const checked = d.action === a.value
                return (
                  <label
                    key={a.value}
                    htmlFor={id}
                    className={`flex min-h-11 flex-1 cursor-pointer items-start gap-2 rounded-lg border p-3 transition-colors ${
                      checked
                        ? "border-primary bg-primary/10"
                        : "border-border bg-background hover:border-primary/50"
                    }`}
                  >
                    <input
                      id={id}
                      type="radio"
                      name={`dup-${d.row.key}`}
                      value={a.value}
                      checked={checked}
                      onChange={() => onChangeAction(d.row.key, a.value)}
                      className="mt-1 size-4 shrink-0 accent-primary"
                    />
                    <span className="flex flex-col">
                      <span className="text-sm font-bold text-foreground">{a.label}</span>
                      <span className="text-xs font-medium text-muted-foreground">{a.hint}</span>
                    </span>
                  </label>
                )
              })}
            </fieldset>
          </li>
        ))}
      </ul>

      <div className="flex items-center justify-end gap-3">
        <button
          type="button"
          onClick={onCancel}
          className="inline-flex h-11 items-center justify-center gap-2 rounded-lg border border-border bg-card px-5 font-bold text-foreground transition-colors hover:border-primary/50 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
        >
          Tilbake til tabellen
        </button>
        <button
          type="button"
          onClick={onContinue}
          className="inline-flex h-11 items-center justify-center gap-2 rounded-lg bg-primary px-5 font-bold text-primary-foreground shadow-sm transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
        >
          Fortsett importen
        </button>
      </div>
    </div>
  )
}
