import { useMutation, useQuery } from '@tanstack/react-query'
import { AlertTriangle } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { qk } from '@/shared/api/query-keys'
import type { GridGenerationMode, GridPlanSlotDto, GridProfileKind } from '@/shared/api/types'
import { cn } from '@/shared/lib/cn'
import { Badge } from '@/shared/ui/badge'
import { Button } from '@/shared/ui/button'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/shared/ui/dialog'
import { toast } from '@/shared/ui/toast-store'
import { DurationLabel } from '../../groups/DurationLabel'
import { generateGrid, listGridProfiles, previewGrid } from '../api'

/**
 * Автосборка сетки: профиль + режим → предпросмотр → создание. План с клиента не уезжает —
 * команда пересчитывает его сама, поэтому показанное и созданное не могут разойтись.
 *
 * Предпросмотр обязателен именно из-за режима пересборки: он сносит все слоты шаблона, и увидеть,
 * что взамен, надо до нажатия, а не после.
 */
export function GenerateGridDialog({
  channelId,
  onClose,
  onGenerated,
  onError,
}: Readonly<{
  channelId: string
  onClose: () => void
  onGenerated: () => void
  onError: (error: unknown) => void
}>) {
  const { t } = useTranslation()
  const [profile, setProfile] = useState<GridProfileKind>('Mixed')
  const [mode, setMode] = useState<GridGenerationMode>('FillGaps')

  const { data: profiles } = useQuery({
    queryKey: qk.gridProfiles.all,
    queryFn: listGridProfiles,
  })

  const { data: plan, isFetching } = useQuery({
    queryKey: qk.channels.gridPlan(channelId, profile, mode),
    queryFn: () => previewGrid(channelId, profile, mode),
    staleTime: 0,
    gcTime: 0,
  })

  const generate = useMutation({
    mutationFn: () => generateGrid(channelId, profile, mode),
    onSuccess: (result) => {
      toast.success(
        t('admin.channels.generate.done', { created: result.created, removed: result.removed }),
      )
      onGenerated()
      onClose()
    },
    onError,
  })

  const covered =
    plan && plan.freeMinutes > 0 ? Math.round((plan.coveredMinutes / plan.freeMinutes) * 100) : 0

  return (
    <Dialog open onOpenChange={(next) => !next && onClose()}>
      {/* Окно не выше экрана: список слотов на неделю длинный, и без ограничения диалог вылезал
          за оба края — верх с выбором профиля становился недостижим. Скроллится тело, шапка
          и кнопки остаются на месте. */}
      <DialogContent className="flex max-h-[90vh] w-[calc(100%-2rem)] max-w-5xl flex-col">
        <DialogHeader>
          <DialogTitle>{t('admin.channels.generate.title')}</DialogTitle>
          <DialogDescription>{t('admin.channels.generate.hint')}</DialogDescription>
        </DialogHeader>

        <div className="flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto pr-1 text-sm">
          {/* Профиль — то, ради чего окно и открыли: ритм суток задаёт всё остальное. */}
          <div className="grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3">
            {(profiles ?? []).map((item) => (
              <button
                key={item.kind}
                type="button"
                className={cn(
                  'flex flex-col items-start gap-0.5 rounded-md border px-3 py-2 text-left transition-colors',
                  item.kind === profile
                    ? 'border-primary bg-primary/10'
                    : 'border-border hover:border-primary/50',
                )}
                onClick={() => setProfile(item.kind)}
              >
                <span className="flex items-baseline gap-2">
                  <span className="font-medium">{item.name}</span>
                  <span className="text-xs text-muted-foreground">{item.reference}</span>
                </span>
                <span className="text-xs text-muted-foreground">{item.description}</span>
              </button>
            ))}
          </div>

          <div className="flex flex-wrap items-center gap-2">
            {(['FillGaps', 'Rebuild'] as const).map((value) => (
              <Button
                key={value}
                size="sm"
                variant={value === mode ? 'default' : 'outline'}
                onClick={() => setMode(value)}
              >
                {t(`admin.channels.generate.modes.${value}`)}
              </Button>
            ))}
            <span className="text-xs text-muted-foreground">
              {t(`admin.channels.generate.modeHints.${mode}`)}
            </span>
          </div>

          {isFetching && <p className="text-muted-foreground">{t('common.loading')}</p>}

          {plan && !isFetching && (
            <>
              <p className="text-muted-foreground">
                {t('admin.channels.generate.summary', {
                  slots: plan.slots.length,
                  percent: covered,
                })}
              </p>

              {plan.slotsToRemove > 0 && (
                <p className="flex items-center gap-1.5 text-amber-500">
                  <AlertTriangle className="h-4 w-4 shrink-0" />
                  {t('admin.channels.generate.willRemove', { count: plan.slotsToRemove })}
                </p>
              )}

              {plan.fallbackGroupName && (
                <p className="text-xs text-muted-foreground">
                  {t('admin.channels.generate.fallback', { name: plan.fallbackGroupName })}
                </p>
              )}

              {/* Замечания разделены по цвету: красное останется дырой в эфире, янтарное —
                  повод посмотреть, но сетка соберётся. */}
              {plan.notes.length > 0 && (
                <ul className="flex flex-col gap-0.5 text-xs">
                  {plan.notes.map((note) => (
                    <li
                      key={note.text}
                      className={note.isError ? 'text-red-500' : 'text-amber-500'}
                    >
                      {note.text}
                    </li>
                  ))}
                </ul>
              )}

              {plan.slots.length === 0 ? (
                <p className="text-muted-foreground">{t('admin.channels.generate.nothing')}</p>
              ) : (
                <ul className="crt-panel divide-y divide-border rounded-md text-xs">
                  {plan.slots.map((slot, index) => (
                    <PlanRow key={`${slot.weekday}-${slot.start}-${index}`} slot={slot} />
                  ))}
                </ul>
              )}
            </>
          )}
        </div>

        <DialogFooter>
          <Button size="sm" variant="outline" onClick={onClose}>
            {t('common.cancel')}
          </Button>
          <Button
            size="sm"
            disabled={generate.isPending || isFetching || !plan || plan.slots.length === 0}
            onClick={() => generate.mutate()}
          >
            {t('admin.channels.generate.create')}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}

function PlanRow({ slot }: Readonly<{ slot: GridPlanSlotDto }>) {
  const { t } = useTranslation()

  return (
    <li className="flex items-center gap-2 px-3 py-1">
      <span className="w-24 shrink-0 text-muted-foreground">
        {slot.weekday === null
          ? t('admin.channels.everyDay')
          : t(`admin.channels.weekdays.${slot.weekday}`)}
      </span>
      <span className="w-12 shrink-0 tabular-nums">{slot.start}</span>
      <span className="w-20 shrink-0 tabular-nums text-muted-foreground">
        <DurationLabel seconds={slot.durationMinutes * 60} />
      </span>
      <span className="min-w-0 flex-1 truncate">{slot.title}</span>
      <Badge variant="muted">{slot.block}</Badge>
    </li>
  )
}
