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

interface ShinyEncounterModalProps {
  routes: Route[]
  gameId: number
  onSubmit: (data: {
    routeId: number
    pokemonId: number
    nickname?: string
    status: 'caught'
    catchLevel?: number
    isShiny: true
  }) => void
  onClose: () => void
  isPending: boolean
}

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 }))
}

export function ShinyEncounterModal({
  routes,
  gameId,
  onSubmit,
  onClose,
  isPending,
}: ShinyEncounterModalProps) {
  const [selectedRouteId, setSelectedRouteId] = useState<number | null>(null)
  const { data: routePokemon, isLoading: loadingPokemon } = useRoutePokemon(
    selectedRouteId,
    gameId,
  )

  const [selectedPokemon, setSelectedPokemon] =
    useState<RouteEncounterDetail | null>(null)
  const [nickname, setNickname] = useState('')
  const [catchLevel, setCatchLevel] = useState<string>('')
  const [search, setSearch] = useState('')

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

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

  // Reset selection when route changes
  const handleRouteChange = (routeId: number) => {
    setSelectedRouteId(routeId)
    setSelectedPokemon(null)
    setSearch('')
  }

  const handleSubmit = () => {
    if (selectedPokemon && selectedRouteId) {
      onSubmit({
        routeId: selectedRouteId,
        pokemonId: selectedPokemon.pokemonId,
        nickname: nickname || undefined,
        status: 'caught',
        catchLevel: catchLevel ? Number(catchLevel) : undefined,
        isShiny: true,
      })
    }
  }

  // Only show leaf routes (no children, i.e. routes that aren't parents)
  const parentIds = new Set(routes.filter(r => r.parentRouteId !== null).map(r => r.parentRouteId))
  const leafRoutes = routes.filter(r => !parentIds.has(r.id))

  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-yellow-300 dark:border-yellow-600 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 flex items-center gap-2">
              <span className="text-yellow-500">&#10022;</span>
              Log Shiny 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-yellow-600 dark:text-yellow-400 mt-1">
            Shiny catches bypass the one-per-route rule
          </p>
        </div>

        <div className="px-6 py-4 space-y-4">
          {/* Route selector */}
          <div>
            <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
              Route
            </label>
            <select
              value={selectedRouteId ?? ''}
              onChange={(e) => handleRouteChange(Number(e.target.value))}
              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-yellow-500"
            >
              <option value="">Select a route...</option>
              {leafRoutes.map((r) => (
                <option key={r.id} value={r.id}>
                  {r.name}
                </option>
              ))}
            </select>
          </div>

          {/* Pokemon Selection */}
          {selectedRouteId && (
            <div>
              <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                Pokemon
              </label>
              {loadingPokemon ? (
                <div className="flex items-center justify-center py-4">
                  <div className="w-6 h-6 border-2 border-yellow-500 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-yellow-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) => (
                            <button
                              key={rp.id}
                              type="button"
                              onClick={() => setSelectedPokemon(rp)}
                              className={`flex flex-col items-center p-2 rounded-lg border text-center transition-colors ${
                                selectedPokemon?.id === rp.id
                                  ? 'border-yellow-500 bg-yellow-50 dark:bg-yellow-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>
                              {SPECIAL_METHODS.includes(rp.encounterMethod) && (
                                <EncounterMethodBadge method={rp.encounterMethod} />
                              )}
                              <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>
          )}

          {/* Nickname */}
          {selectedPokemon && (
            <div>
              <label
                htmlFor="shiny-nickname"
                className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
              >
                Nickname
              </label>
              <input
                id="shiny-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-yellow-500"
              />
            </div>
          )}

          {/* Catch Level */}
          {selectedPokemon && (
            <div>
              <label
                htmlFor="shiny-catch-level"
                className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
              >
                Catch Level
              </label>
              <input
                id="shiny-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-yellow-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={!selectedPokemon || isPending}
            onClick={handleSubmit}
            className="px-4 py-2 bg-yellow-500 text-white rounded-lg font-medium hover:bg-yellow-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
          >
            {isPending ? 'Saving...' : 'Log Shiny'}
          </button>
        </div>
      </div>
    </div>
  )
}
