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, CalledItAvatar, CalledItButton, CalledItCard, CalledItConfirmDialog, CalledItDialog, CalledItLogoUpload, CalledItTextInput } from '../components'
import {
  competitionLogoUrl,
  createCompetition,
  deleteCompetition,
  fetchCompetitions,
  updateCompetition,
  uploadCompetitionLogo,
  type CompetitionResponse,
} from '../features/competitions/competitionApi'
import { useToast } from '../hooks/useToast'
import { formatDate } from '../utils/dateFormat'
import type { AppOutletContext } from '../types/auth'

type FormState = {
  name: string
  startDate: string
  endDate: string
  description: string
}

type FormErrors = {
  name?: string
  startDate?: string
  endDate?: string
}

const emptyForm: FormState = { name: '', startDate: '', endDate: '', description: '' }

function validate(form: FormState): FormErrors {
  const errors: FormErrors = {}
  if (!form.name.trim()) errors.name = 'Required'
  if (!form.startDate) errors.startDate = 'Required'
  if (!form.endDate) errors.endDate = 'Required'
  else if (form.startDate && form.endDate <= form.startDate)
    errors.endDate = 'Must be after start date'
  return errors
}

export function AdminCompetitionsPage() {
  const { session, refetchCompetitions } = useOutletContext<AppOutletContext>()

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

  const { toast, showError, dismiss } = useToast()
  const [competitions, setCompetitions] = useState<CompetitionResponse[]>([])
  const [modalOpen, setModalOpen] = useState(false)
  const [form, setForm] = useState<FormState>(emptyForm)
  const [fieldErrors, setFieldErrors] = useState<FormErrors>({})
  const [editingId, setEditingId] = useState<number | null>(null)
  const [pendingLogo, setPendingLogo] = useState<File | null>(null)
  const [previewUrl, setPreviewUrl] = useState<string | undefined>()
  const [loading, setLoading] = useState(false)
  const [confirmOpen, setConfirmOpen] = useState(false)
  const [pendingDeleteId, setPendingDeleteId] = useState<number | null>(null)

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

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

  function openEdit(competition: CompetitionResponse) {
    setEditingId(competition.id)
    setForm({
      name: competition.name,
      startDate: competition.startDate.slice(0, 10),
      endDate: competition.endDate.slice(0, 10),
      description: competition.description,
    })
    setFieldErrors({})
    setPendingLogo(null)
    setPreviewUrl(competitionLogoUrl(competition.logoUrl))
    setModalOpen(true)
  }

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

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

  function handleLogoSelect(file: File) {
    setPendingLogo(file)
    setPreviewUrl(URL.createObjectURL(file))
  }

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

    setLoading(true)
    try {
      const dto = {
        name: form.name,
        startDate: new Date(form.startDate).toISOString(),
        endDate: new Date(form.endDate).toISOString(),
        description: form.description,
      }

      let saved: CompetitionResponse
      if (editingId !== null) {
        saved = await updateCompetition(session.token, editingId, dto)
      } else {
        saved = await createCompetition(session.token, dto)
      }

      if (pendingLogo) {
        saved = await uploadCompetitionLogo(session.token, saved.id, pendingLogo)
      }

      setCompetitions((prev) =>
        editingId !== null
          ? prev.map((c) => (c.id === saved.id ? saved : c))
          : [...prev, saved],
      )
      refetchCompetitions()
      closeModal()
    } catch (err: unknown) {
      showError(
        editingId !== null ? 'Failed to update competition' : 'Failed to create competition',
        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 deleteCompetition(session.token, pendingDeleteId)
      setCompetitions((prev) => prev.filter((c) => c.id !== pendingDeleteId))
      refetchCompetitions()
    } catch (err: unknown) {
      showError('Failed to delete competition', 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 Competition"
        description="This will permanently delete the competition and all its associated data. This action cannot be undone."
      />

      <CalledItDialog
        open={modalOpen}
        onClose={closeModal}
        title={editingId !== null ? 'Edit Competition' : 'New Competition'}
        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">
          <CalledItTextInput
            label="Name"
            value={form.name}
            errorText={fieldErrors.name}
            onChange={(e) => setField('name', e.target.value)}
          />
          <CalledItTextInput
            label="Start Date"
            type="date"
            value={form.startDate}
            errorText={fieldErrors.startDate}
            onChange={(e) => setField('startDate', e.target.value)}
          />
          <CalledItTextInput
            label="End Date"
            type="date"
            value={form.endDate}
            errorText={fieldErrors.endDate}
            onChange={(e) => setField('endDate', e.target.value)}
          />
          <CalledItTextInput
            label="Description"
            value={form.description}
            onChange={(e) => setField('description', e.target.value)}
          />
          <CalledItLogoUpload
            currentLogoUrl={previewUrl}
            onFileSelect={handleLogoSelect}
          />
        </Stack>
      </CalledItDialog>

      <CalledItCard cardTitle="Competitions">
        <CalledItButton size="sm" colorPalette="brand" onClick={openCreate} mb="4">
          <Plus size={16} /> New Competition
        </CalledItButton>
        <Stack gap="2">
          {competitions.length === 0 && (
            <Text color="muted" fontSize="sm">No competitions yet.</Text>
          )}
          {competitions.map((competition) => (
            <Flex key={competition.id} align="center" justify="space-between" py="2" borderBottomWidth="1px" borderColor="border">
              <Flex align="center" gap="3">
                <CalledItAvatar src={competitionLogoUrl(competition.logoUrl)} name={competition.name} size="sm" />
                <Stack gap="0">
                  <Text fontWeight="600" color="heading">{competition.name}</Text>
                  <Text fontSize="sm" color="muted">
                    {formatDate(competition.startDate)} – {formatDate(competition.endDate)}
                  </Text>
                </Stack>
              </Flex>
              <Flex gap="1">
                <IconButton size="sm" variant="ghost" aria-label="Edit" onClick={() => openEdit(competition)}>
                  <Pencil size={16} />
                </IconButton>
                <IconButton size="sm" variant="ghost" colorPalette="red" aria-label="Delete" onClick={() => requestDelete(competition.id)}>
                  <Trash2 size={16} />
                </IconButton>
              </Flex>
            </Flex>
          ))}
        </Stack>
      </CalledItCard>
    </>
  )
}
