import { useState, useEffect, useMemo } from 'react'
import { useRoutePokemon } from '../hooks/useGames'
import {
  EncounterMethodBadge,
  getMethodLabel,
  METHOD_ORDER,
} from './EncounterMethodBadge'
import type {
  Route,
  EncounterDetail,
  EncounterStatus,
  RouteEncounterDetail,
} from '../types'

interface EncounterModalProps {
  route: Route
  gameId: number
  existing?: EncounterDetail
  dupedPokemonIds?: Set<number>
  retiredPokemonIds?: Set<number>
  onSubmit: (data: {
    routeId: number
    pokemonId: number
    nickname?: string
    status: EncounterStatus
    catchLevel?: number
  }) => void
  onUpdate?: (data: {
    id: number
    data: {
      nickname?: string
      status?: EncounterStatus
      faintLevel?: number
      deathCause?: string
    }
  }) => void
  onClose: () => void
  isPending: boolean
}

const statusOptions: { value: EncounterStatus; label: string; color: string }[] =
  [
    {
      value: 'caught',
      label: 'Caught',
      color:
        'bg-green-100 text-green-800 border-green-300 dark:bg-green-900/40 dark:text-green-300 dark:border-green-700',
    },
    {
      value: 'fainted',
      label: 'Fainted',
      color:
        'bg-red-100 text-red-800 border-red-300 dark:bg-red-900/40 dark:text-red-300 dark:border-red-700',
    },
    {
      value: 'missed',
      label: 'Missed / Ran',
      color:
        'bg-gray-100 text-gray-800 border-gray-300 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600',
    },
  ]

const SPECIAL_METHODS = ['starter', 'gift', 'fossil', 'trade']

function groupByMethod(pokemon: RouteEncounterDetail[]): { method: string; pokemon: RouteEncounterDetail[] }[] {
  const groups = new Map<string, RouteEncounterDetail[]>()
  for (const rp of pokemon) {
    const list = groups.get(rp.encounterMethod) ?? []
    list.push(rp)
    groups.set(rp.encounterMethod, list)
  }
  return [...groups.entries()]
    .sort(([a], [b]) => {
      const ai = METHOD_ORDER.indexOf(a)
      const bi = METHOD_ORDER.indexOf(b)
      return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi)
    })
    .map(([method, pokemon]) => ({ method, pokemon }))
}

function pickRandomPokemon(
  pokemon: RouteEncounterDetail[],
  dupedIds?: Set<number>,
): RouteEncounterDetail | null {
  const eligible = dupedIds
    ? pokemon.filter((rp) => !dupedIds.has(rp.pokemonId))
    : pokemon
  if (eligible.length === 0) return null
  return eligible[Math.floor(Math.random() * eligible.length)]
}

export function EncounterModal({
  route,
  gameId,
  existing,
  dupedPokemonIds,
  retiredPokemonIds,
  onSubmit,
  onUpdate,
  onClose,
  isPending,
}: EncounterModalProps) {
  const { data: routePokemon, isLoading: loadingPokemon } = useRoutePokemon(
    route.id,
    gameId,
  )

  const [selectedPokemon, setSelectedPokemon] =
    useState<RouteEncounterDetail | null>(null)
  const [status, setStatus] = useState<EncounterStatus>(
    existing?.status ?? 'caught',
  )
  const [nickname, setNickname] = useState(existing?.nickname ?? '')
  const [catchLevel, setCatchLevel] = useState<string>(
    existing?.catchLevel?.toString() ?? '',
  )
  const [faintLevel, setFaintLevel] = useState<string>('')
  const [deathCause, setDeathCause] = useState('')
  const [search, setSearch] = useState('')

  const isEditing = !!existing

  // Pre-select pokemon when editing
  useEffect(() => {
    if (existing && routePokemon) {
      const match = routePokemon.find(
        (rp) => rp.pokemonId === existing.pokemonId,
      )
      if (match) setSelectedPokemon(match)
    }
  }, [existing, routePokemon])

  const filteredPokemon = routePokemon?.filter((rp) =>
    rp.pokemon.name.toLowerCase().includes(search.toLowerCase()),
  )

  const groupedPokemon = useMemo(
    () => (filteredPokemon ? groupByMethod(filteredPokemon) : []),
    [filteredPokemon],
  )
  const hasMultipleGroups = groupedPokemon.length > 1

  const handleSubmit = () => {
    if (isEditing && onUpdate) {
      onUpdate({
        id: existing.id,
        data: {
          nickname: nickname || undefined,
          status,
          faintLevel: faintLevel ? Number(faintLevel) : undefined,
          deathCause: deathCause || undefined,
        },
      })
    } else if (selectedPokemon) {
      onSubmit({
        routeId: route.id,
        pokemonId: selectedPokemon.pokemonId,
        nickname: nickname || undefined,
        status,
        catchLevel: catchLevel ? Number(catchLevel) : undefined,
      })
    }
  }

  const canSubmit = isEditing || selectedPokemon

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center p-4">
      <div className="fixed inset-0 bg-black/50" onClick={onClose} />
      <div className="relative bg-white dark:bg-gray-800 rounded-xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto">
        <div className="sticky top-0 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-6 py-4 rounded-t-xl">
          <div className="flex items-center justify-between">
            <h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100">
              {isEditing ? 'Edit Encounter' : 'Log Encounter'}
            </h2>
            <button
              onClick={onClose}
              className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
            >
              <svg
                className="w-5 h-5"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M6 18L18 6M6 6l12 12"
                />
              </svg>
            </button>
          </div>
          <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
            {route.name}
          </p>
        </div>

        <div className="px-6 py-4 space-y-4">
          {/* Pokemon Selection (only for new encounters) */}
          {!isEditing && (
            <div>
              <div className="flex items-center justify-between mb-1">
                <label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
                  Pokemon
                </label>
                {!loadingPokemon && routePokemon && routePokemon.length > 0 && (
                  <button
                    type="button"
                    disabled={
                      loadingPokemon ||
                      !routePokemon ||
                      (dupedPokemonIds
                        ? routePokemon.every((rp) => dupedPokemonIds.has(rp.pokemonId))
                        : false)
                    }
                    onClick={() => {
                      if (routePokemon) {
                        setSelectedPokemon(
                          pickRandomPokemon(routePokemon, dupedPokemonIds),
                        )
                      }
                    }}
                    className="px-2.5 py-1 text-xs font-medium rounded-lg border border-purple-300 dark:border-purple-600 text-purple-600 dark:text-purple-400 hover:bg-purple-50 dark:hover:bg-purple-900/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
                  >
                    {selectedPokemon ? 'Re-roll' : 'Randomize'}
                  </button>
                )}
              </div>
              {loadingPokemon ? (
                <div className="flex items-center justify-center py-4">
                  <div className="w-10 h-10 border-2 border-blue-600 border-t-transparent rounded-full animate-spin" />
                </div>
              ) : filteredPokemon && filteredPokemon.length > 0 ? (
                <>
                  {(routePokemon?.length ?? 0) > 6 && (
                    <input
                      type="text"
                      placeholder="Search pokemon..."
                      value={search}
                      onChange={(e) => setSearch(e.target.value)}
                      className="w-full px-3 py-1.5 mb-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                    />
                  )}
                  <div className="max-h-64 overflow-y-auto space-y-3">
                    {groupedPokemon.map(({ method, pokemon }, groupIdx) => (
                      <div key={method}>
                        {groupIdx > 0 && (
                          <div className="border-t border-gray-200 dark:border-gray-700 mb-3" />
                        )}
                        {hasMultipleGroups && (
                          <div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1.5">
                            {getMethodLabel(method)}
                          </div>
                        )}
                        <div className="grid grid-cols-3 gap-2">
                          {pokemon.map((rp) => {
                            const isDuped = dupedPokemonIds?.has(rp.pokemonId) ?? false
                            return (
                              <button
                                key={rp.id}
                                type="button"
                                onClick={() => !isDuped && setSelectedPokemon(rp)}
                                disabled={isDuped}
                                className={`flex flex-col items-center p-2 rounded-lg border text-center transition-colors ${
                                  isDuped
                                    ? 'opacity-40 cursor-not-allowed border-gray-200 dark:border-gray-700'
                                    : selectedPokemon?.id === rp.id
                                      ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/30'
                                      : 'border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600'
                                }`}
                              >
                                {rp.pokemon.spriteUrl ? (
                                  <img
                                    src={rp.pokemon.spriteUrl}
                                    alt={rp.pokemon.name}
                                    className="w-10 h-10"
                                  />
                                ) : (
                                  <div className="w-10 h-10 rounded-full bg-gray-200 dark:bg-gray-600 flex items-center justify-center text-xs font-bold">
                                    {rp.pokemon.name[0].toUpperCase()}
                                  </div>
                                )}
                                <span className="text-xs text-gray-700 dark:text-gray-300 mt-1 capitalize">
                                  {rp.pokemon.name}
                                </span>
                                {isDuped && (
                                  <span className="text-[10px] text-gray-400 italic">
                                    {retiredPokemonIds?.has(rp.pokemonId) ? 'retired (HoF)' : 'already caught'}
                                  </span>
                                )}
                                {!isDuped && SPECIAL_METHODS.includes(rp.encounterMethod) && (
                                  <EncounterMethodBadge method={rp.encounterMethod} />
                                )}
                                {!isDuped && (
                                  <span className="text-[10px] text-gray-400">
                                    Lv. {rp.minLevel}
                                    {rp.maxLevel !== rp.minLevel && `–${rp.maxLevel}`}
                                  </span>
                                )}
                              </button>
                            )
                          })}
                        </div>
                      </div>
                    ))}
                  </div>
                </>
              ) : (
                <p className="text-sm text-gray-500 dark:text-gray-400 py-2">
                  No pokemon data for this route
                </p>
              )}
            </div>
          )}

          {/* Editing: show pokemon info */}
          {isEditing && existing && (
            <div className="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-900/50 rounded-lg">
              {existing.pokemon.spriteUrl ? (
                <img
                  src={existing.pokemon.spriteUrl}
                  alt={existing.pokemon.name}
                  className="w-12 h-12"
                />
              ) : (
                <div className="w-12 h-12 rounded-full bg-gray-200 dark:bg-gray-600 flex items-center justify-center text-lg font-bold">
                  {existing.pokemon.name[0].toUpperCase()}
                </div>
              )}
              <div>
                <div className="font-medium text-gray-900 dark:text-gray-100 capitalize">
                  {existing.pokemon.name}
                </div>
                <div className="text-xs text-gray-500">
                  Caught at Lv. {existing.catchLevel ?? '?'}
                </div>
              </div>
            </div>
          )}

          {/* Status */}
          <div>
            <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
              Status
            </label>
            <div className="flex gap-2">
              {statusOptions.map((opt) => (
                <button
                  key={opt.value}
                  type="button"
                  onClick={() => setStatus(opt.value)}
                  className={`flex-1 px-3 py-2 rounded-lg border text-sm font-medium transition-colors ${
                    status === opt.value
                      ? opt.color
                      : 'border-gray-200 dark:border-gray-700 text-gray-500 dark:text-gray-400 hover:border-gray-300'
                  }`}
                >
                  {opt.label}
                </button>
              ))}
            </div>
          </div>

          {/* Nickname (for caught) */}
          {status === 'caught' && (
            <div>
              <label
                htmlFor="nickname"
                className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
              >
                Nickname
              </label>
              <input
                id="nickname"
                type="text"
                value={nickname}
                onChange={(e) => setNickname(e.target.value)}
                placeholder="Give it a name..."
                className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
              />
            </div>
          )}

          {/* Level (for new caught encounters) */}
          {!isEditing && status === 'caught' && (
            <div>
              <label
                htmlFor="catch-level"
                className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
              >
                Catch Level
              </label>
              <input
                id="catch-level"
                type="number"
                min={1}
                max={100}
                value={catchLevel}
                onChange={(e) => setCatchLevel(e.target.value)}
                placeholder={
                  selectedPokemon
                    ? `${selectedPokemon.minLevel}–${selectedPokemon.maxLevel}`
                    : 'Level'
                }
                className="w-24 px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
              />
            </div>
          )}

          {/* Faint Level + Death Cause (only when editing a caught pokemon to mark dead) */}
          {isEditing &&
            existing?.status === 'caught' &&
            existing?.faintLevel === null && (
              <>
                <div>
                  <label
                    htmlFor="faint-level"
                    className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                  >
                    Faint Level{' '}
                    <span className="font-normal text-gray-400">
                      (mark as dead)
                    </span>
                  </label>
                  <input
                    id="faint-level"
                    type="number"
                    min={1}
                    max={100}
                    value={faintLevel}
                    onChange={(e) => setFaintLevel(e.target.value)}
                    placeholder="Leave empty if still alive"
                    className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
                  />
                </div>
                <div>
                  <label
                    htmlFor="death-cause"
                    className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                  >
                    Cause of Death{' '}
                    <span className="font-normal text-gray-400">
                      (optional)
                    </span>
                  </label>
                  <input
                    id="death-cause"
                    type="text"
                    maxLength={100}
                    value={deathCause}
                    onChange={(e) => setDeathCause(e.target.value)}
                    placeholder="e.g. Crit from rival's Charizard"
                    className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
                  />
                </div>
              </>
            )}
        </div>

        <div className="sticky bottom-0 bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 px-6 py-4 rounded-b-xl flex justify-end gap-3">
          <button
            type="button"
            onClick={onClose}
            className="px-4 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
          >
            Cancel
          </button>
          <button
            type="button"
            disabled={!canSubmit || isPending}
            onClick={handleSubmit}
            className="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
          >
            {isPending
              ? 'Saving...'
              : isEditing
                ? 'Update'
                : 'Log Encounter'}
          </button>
        </div>
      </div>
    </div>
  )
}
