import { Flex, IconButton, Stack, Text } from '@chakra-ui/react'
import { Pencil, Plus, Trash2 } from 'lucide-react'
import { useEffect, useState } from 'react'
import { Navigate, useOutletContext } from 'react-router-dom'
import { CalledItAlert, CalledItButton, CalledItCard, CalledItConfirmDialog, CalledItDialog, CalledItSelect, CalledItTextInput } from '../components'
import type { SelectOption } from '../components/CalledItSelect'
import {
  createMatch,
  deleteMatch,
  fetchMatches,
  updateMatch,
  type MatchResponse,
} from '../features/matches/matchApi'
import { fetchTeams, type TeamResponse } from '../features/teams/teamApi'
import { useToast } from '../hooks/useToast'
import { formatDateTime } from '../utils/dateFormat'
import type { AppOutletContext } from '../types/auth'

type FormState = {
  homeTeamId: string
  awayTeamId: string
  matchDate: string
  round: string
  homeScore: string
  awayScore: string
}

type FormErrors = {
  homeTeamId?: string
  awayTeamId?: string
  matchDate?: string
  round?: string
}

const emptyForm: FormState = {
  homeTeamId: '',
  awayTeamId: '',
  matchDate: '',
  round: '',
  homeScore: '',
  awayScore: '',
}

function validate(form: FormState): FormErrors {
  const errors: FormErrors = {}
  if (!form.homeTeamId) errors.homeTeamId = 'Required'
  if (!form.awayTeamId) errors.awayTeamId = 'Required'
  else if (form.homeTeamId && form.awayTeamId === form.homeTeamId)
    errors.awayTeamId = 'Must be different from home team'
  if (!form.matchDate) errors.matchDate = 'Required'
  if (!form.round.trim()) errors.round = 'Required'
  return errors
}

export function AdminMatchesPage() {
  const { session, selectedCompetitionId } = useOutletContext<AppOutletContext>()

  if (!session.isAdmin) {
    return <Navigate to="/" replace />
  }

  const { toast, showError, dismiss } = useToast()
  const [matches, setMatches] = useState<MatchResponse[]>([])
  const [teams, setTeams] = useState<TeamResponse[]>([])
  const [modalOpen, setModalOpen] = useState(false)
  const [form, setForm] = useState<FormState>(emptyForm)
  const [fieldErrors, setFieldErrors] = useState<FormErrors>({})
  const [editingId, setEditingId] = useState<number | null>(null)
  const [loading, setLoading] = useState(false)
  const [confirmOpen, setConfirmOpen] = useState(false)
  const [pendingDeleteId, setPendingDeleteId] = useState<number | null>(null)

  const competitionId = selectedCompetitionId ? Number(selectedCompetitionId) : null

  useEffect(() => {
    fetchTeams(session.token)
      .then(setTeams)
      .catch((err: unknown) => showError('Failed to load teams', err instanceof Error ? err.message : String(err)))
  }, [session.token])

  useEffect(() => {
    if (competitionId === null) return
    fetchMatches(session.token, competitionId)
      .then(setMatches)
      .catch((err: unknown) => showError('Failed to load matches', err instanceof Error ? err.message : String(err)))
  }, [session.token, competitionId])

  if (competitionId === null) {
    return (
      <CalledItCard cardTitle="Manage Matches">
        <Text color="muted">Select a competition from the header to manage its matches.</Text>
      </CalledItCard>
    )
  }

  const teamOptions: SelectOption[] = teams.map((t) => ({ label: t.name, value: String(t.id) }))

  function openCreate() {
    setEditingId(null)
    setForm(emptyForm)
    setFieldErrors({})
    setModalOpen(true)
  }

  function openEdit(match: MatchResponse) {
    setEditingId(match.id)
    setForm({
      homeTeamId: String(match.homeTeam.id),
      awayTeamId: String(match.awayTeam.id),
      matchDate: match.matchDate.slice(0, 16),
      round: match.round,
      homeScore: match.homeScore !== null ? String(match.homeScore) : '',
      awayScore: match.awayScore !== null ? String(match.awayScore) : '',
    })
    setFieldErrors({})
    setModalOpen(true)
  }

  function closeModal() {
    setModalOpen(false)
    setForm(emptyForm)
    setEditingId(null)
    setFieldErrors({})
  }

  function setField<K extends keyof FormState>(key: K, value: FormState[K]) {
    setForm((f) => ({ ...f, [key]: value }))
    setFieldErrors((e) => ({ ...e, [key]: undefined }))
  }

  async function handleSubmit() {
    const errors = validate(form)
    if (Object.keys(errors).length > 0) {
      setFieldErrors(errors)
      return
    }

    setLoading(true)
    try {
      if (competitionId === null) return
      if (editingId !== null) {
        const dto = {
          competitionId,
          homeTeamId: Number(form.homeTeamId),
          awayTeamId: Number(form.awayTeamId),
          matchDate: new Date(form.matchDate).toISOString(),
          round: form.round,
          homeScore: form.homeScore !== '' ? Number(form.homeScore) : null,
          awayScore: form.awayScore !== '' ? Number(form.awayScore) : null,
        }
        const updated = await updateMatch(session.token, editingId, dto)
        setMatches((prev) => prev.map((m) => (m.id === editingId ? updated : m)))
      } else {
        const dto = {
          competitionId,
          homeTeamId: Number(form.homeTeamId),
          awayTeamId: Number(form.awayTeamId),
          matchDate: new Date(form.matchDate).toISOString(),
          round: form.round,
        }
        const created = await createMatch(session.token, dto)
        setMatches((prev) => [...prev, created])
      }
      closeModal()
    } catch (err: unknown) {
      showError(
        editingId !== null ? 'Failed to update match' : 'Failed to create match',
        err instanceof Error ? err.message : String(err),
      )
    } finally {
      setLoading(false)
    }
  }

  function requestDelete(id: number) {
    setPendingDeleteId(id)
    setConfirmOpen(true)
  }

  async function confirmDelete() {
    if (pendingDeleteId === null) return
    setConfirmOpen(false)
    try {
      await deleteMatch(session.token, pendingDeleteId)
      setMatches((prev) => prev.filter((m) => m.id !== pendingDeleteId))
    } catch (err: unknown) {
      showError('Failed to delete match', err instanceof Error ? err.message : String(err))
    } finally {
      setPendingDeleteId(null)
    }
  }

  return (
    <>
      {toast && (
        <CalledItAlert
          isToast
          status={toast.status}
          title={toast.title}
          description={toast.description}
          onClose={dismiss}
        />
      )}

      <CalledItConfirmDialog
        open={confirmOpen}
        onClose={() => { setConfirmOpen(false); setPendingDeleteId(null) }}
        onConfirm={confirmDelete}
        title="Delete Match"
        description="This will permanently delete the match. This action cannot be undone."
      />

      <CalledItDialog
        open={modalOpen}
        onClose={closeModal}
        title={editingId !== null ? 'Edit Match' : 'New Match'}
        footer={
          <Flex gap="2">
            <CalledItButton colorPalette="brand" loading={loading} onClick={handleSubmit}>
              {editingId !== null ? 'Save' : 'Create'}
            </CalledItButton>
            <CalledItButton variant="ghost" onClick={closeModal}>Cancel</CalledItButton>
          </Flex>
        }
      >
        <Stack gap="4">
          <CalledItSelect
            options={teamOptions}
            placeholder="Select team"
            label="Home Team"
            errorText={fieldErrors.homeTeamId}
            value={form.homeTeamId ? [form.homeTeamId] : []}
            onValueChange={(e) => setField('homeTeamId', e.value[0] ?? '')}
          />
          <CalledItSelect
            options={teamOptions}
            placeholder="Select team"
            label="Away Team"
            errorText={fieldErrors.awayTeamId}
            value={form.awayTeamId ? [form.awayTeamId] : []}
            onValueChange={(e) => setField('awayTeamId', e.value[0] ?? '')}
          />
          <CalledItTextInput
            label="Match Date & Time"
            type="datetime-local"
            value={form.matchDate}
            errorText={fieldErrors.matchDate}
            onChange={(e) => setField('matchDate', e.target.value)}
          />
          <CalledItTextInput
            label="Round"
            value={form.round}
            errorText={fieldErrors.round}
            onChange={(e) => setField('round', e.target.value)}
          />
          <Flex gap="4">
            <CalledItTextInput
              label="Home Score"
              type="number"
              value={form.homeScore}
              onChange={(e) => {
                const v = e.target.value
                setField('homeScore', v === '' ? '' : String(Math.max(0, Number(v))))
              }}
            />
            <CalledItTextInput
              label="Away Score"
              type="number"
              value={form.awayScore}
              onChange={(e) => {
                const v = e.target.value
                setField('awayScore', v === '' ? '' : String(Math.max(0, Number(v))))
              }}
            />
          </Flex>
        </Stack>
      </CalledItDialog>

      <CalledItCard cardTitle="Matches">
        <CalledItButton size="sm" colorPalette="brand" onClick={openCreate} mb="4">
          <Plus size={16} /> New Match
        </CalledItButton>
        <Stack gap="2">
          {matches.length === 0 && (
            <Text color="muted" fontSize="sm">No matches yet.</Text>
          )}
          {matches.map((match) => (
            <Flex key={match.id} align="center" justify="space-between" py="2" borderBottomWidth="1px" borderColor="border">
              <Stack gap="0">
                <Text fontWeight="600" color="heading">
                  {match.homeTeam.name} vs {match.awayTeam.name}
                </Text>
                <Text fontSize="sm" color="muted">
                  {formatDateTime(match.matchDate)} · Round {match.round}
                  {match.homeScore !== null && ` · ${match.homeScore}–${match.awayScore ?? '?'}`}
                </Text>
              </Stack>
              <Flex gap="1">
                <IconButton size="sm" variant="ghost" aria-label="Edit" onClick={() => openEdit(match)}>
                  <Pencil size={16} />
                </IconButton>
                <IconButton size="sm" variant="ghost" colorPalette="red" aria-label="Delete" onClick={() => requestDelete(match.id)}>
                  <Trash2 size={16} />
                </IconButton>
              </Flex>
            </Flex>
          ))}
        </Stack>
      </CalledItCard>
    </>
  )
}
