import { useMutation, useQuery } from '@tanstack/react-query'
import { Plus, Trash2 } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { listGroups } from '@/features/admin/groups/api'
import { qk } from '@/shared/api/query-keys'
import {
  SHOW_AUDIENCES,
  type AudienceWindow,
  type PlanningRules,
  type ScheduleTemplateDto,
  type ShowAudience,
} from '@/shared/api/types'
import { Button } from '@/shared/ui/button'
import { Input } from '@/shared/ui/input'
import { Label } from '@/shared/ui/label'
import { updateTemplate } from '../api'
import { CollapsibleCard } from './CollapsibleCard'

const EMPTY_WINDOW: AudienceWindow = { from: '06:00:00', to: '23:00:00', maxAudience: 'PG-13' }

/**
 * Окно со стабильным ключом. Индекс в качестве key не годится: строки удаляются из середины, и React
 * сопоставил бы уцелевшие узлы не с теми окнами — фокус и внутреннее состояние полей переехали бы
 * в соседнюю строку. Ключ живёт только на клиенте и в API не уезжает.
 */
type WindowRow = { key: string; window: AudienceWindow }

const toRows = (windows: AudienceWindow[]): WindowRow[] =>
  windows.map((window) => ({ key: crypto.randomUUID(), window }))

/**
 * Правила отбора кандидатов канала (см. 3.8): детское время и потолок повторов. Это жёсткие
 * фильтры — они отсекают недопустимое до жребия, поэтому не требуют пересборки и не ломают
 * воспроизводимость. Как и правка сетки, эфира сами по себе не двигают.
 */
export function RulesCard({
  template,
  bare,
  onChanged,
  onError,
}: Readonly<{
  template: ScheduleTemplateDto
  bare?: boolean
  onChanged: () => void
  onError: (error: unknown) => void
}>) {
  const { t } = useTranslation()
  const [windows, setWindows] = useState<WindowRow[]>(() =>
    toRows(template.rules?.maxAudienceByTime ?? []),
  )
  const [limitOn, setLimitOn] = useState(() => template.rules?.maxRepeatsInWindow != null)
  const [windowDays, setWindowDays] = useState(
    () => template.rules?.maxRepeatsInWindow?.windowDays ?? 7,
  )
  const [max, setMax] = useState(() => template.rules?.maxRepeatsInWindow?.max ?? 2)
  const [breakCap, setBreakCap] = useState(() => template.rules?.maxBreakMinutesPerHour ?? 0)
  const [genreCap, setGenreCap] = useState(() => template.rules?.maxGenreSharePercent ?? 0)
  const [fallbackCap, setFallbackCap] = useState(() => template.rules?.maxFallbackSharePercent ?? 0)
  const [fallbackGroupId, setFallbackGroupId] = useState(() => template.fallbackGroupId)

  // Аварийную группу проставляет и автосборка сетки, поэтому список нужен всегда: без него
  // ссылка остаётся невидимой, а снять её нечем — и группа не удаляется.
  const { data: groups } = useQuery({ queryKey: qk.groups.all, queryFn: listGroups })

  useEffect(() => {
    setWindows(toRows(template.rules?.maxAudienceByTime ?? []))
    setLimitOn(template.rules?.maxRepeatsInWindow != null)
    setWindowDays(template.rules?.maxRepeatsInWindow?.windowDays ?? 7)
    setMax(template.rules?.maxRepeatsInWindow?.max ?? 2)
    setBreakCap(template.rules?.maxBreakMinutesPerHour ?? 0)
    setGenreCap(template.rules?.maxGenreSharePercent ?? 0)
    setFallbackCap(template.rules?.maxFallbackSharePercent ?? 0)
    setFallbackGroupId(template.fallbackGroupId)
  }, [template])

  const save = useMutation({
    mutationFn: () => {
      const rules: PlanningRules = {
        maxAudienceByTime: windows.length > 0 ? windows.map((row) => row.window) : null,
        maxRepeatsInWindow: limitOn ? { windowDays, max } : null,
        // Ноль означает «не проверять»: отдельного выключателя на каждый порог не нужно.
        maxBreakMinutesPerHour: breakCap > 0 ? breakCap : null,
        maxGenreSharePercent: genreCap > 0 ? genreCap : null,
        maxFallbackSharePercent: fallbackCap > 0 ? fallbackCap : null,
      }
      return updateTemplate(template.id, {
        name: template.name,
        fallbackGroupId,
        defaultJunctionId: template.defaultJunctionId,
        rules,
      })
    },
    onSuccess: onChanged,
    onError,
  })

  const removeWindow = (key: string) =>
    setWindows((current) => current.filter((row) => row.key !== key))

  const patchWindow = (key: string, part: Partial<AudienceWindow>) =>
    setWindows((current) =>
      current.map((row) =>
        row.key === key ? { ...row, window: { ...row.window, ...part } } : row,
      ),
    )

  return (
    <CollapsibleCard title={t('admin.channels.rules')} bare={bare}>
      <div className="flex flex-col gap-4 text-sm">
        <p className="text-xs text-muted-foreground">{t('admin.channels.rulesHint')}</p>

        <div className="flex flex-col gap-2">
          <div className="flex items-center justify-between gap-2">
            <h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
              {t('admin.channels.audienceWindows')}
            </h3>
            <Button
              size="sm"
              variant="ghost"
              onClick={() => setWindows((c) => [...c, ...toRows([EMPTY_WINDOW])])}
            >
              <Plus className="h-4 w-4" />
            </Button>
          </div>

          {windows.length === 0 ? (
            <p className="text-xs text-muted-foreground">{t('admin.channels.noAudienceWindows')}</p>
          ) : (
            <ul className="flex flex-col gap-2">
              {windows.map(({ key, window }) => (
                <li key={key} className="flex flex-wrap items-end gap-2">
                  <div className="flex flex-col gap-1.5">
                    <Label>{t('admin.channels.from')}</Label>
                    <Input
                      type="time"
                      className="w-28"
                      value={window.from.slice(0, 5)}
                      onChange={(e) => patchWindow(key, { from: `${e.target.value}:00` })}
                    />
                  </div>
                  <div className="flex flex-col gap-1.5">
                    <Label>{t('admin.channels.to')}</Label>
                    <Input
                      type="time"
                      className="w-28"
                      value={window.to.slice(0, 5)}
                      onChange={(e) => patchWindow(key, { to: `${e.target.value}:00` })}
                    />
                  </div>
                  <div className="flex flex-col gap-1.5">
                    <Label>{t('admin.channels.maxAudience')}</Label>
                    <select
                      className="h-9 rounded-md border border-border bg-transparent px-2"
                      value={window.maxAudience}
                      onChange={(e) =>
                        patchWindow(key, { maxAudience: e.target.value as ShowAudience })
                      }
                    >
                      {SHOW_AUDIENCES.map((value) => (
                        <option key={value} value={value}>
                          {t(`admin.shows.audiences.${value}`)}
                        </option>
                      ))}
                    </select>
                  </div>
                  <Button size="sm" variant="ghost" onClick={() => removeWindow(key)}>
                    <Trash2 className="h-4 w-4" />
                  </Button>
                </li>
              ))}
            </ul>
          )}
          <p className="text-xs text-muted-foreground">{t('admin.channels.audienceWindowsHint')}</p>
        </div>

        <div className="flex flex-col gap-2 border-t border-border pt-4">
          <label className="flex items-center gap-2">
            <input
              type="checkbox"
              checked={limitOn}
              onChange={(e) => setLimitOn(e.target.checked)}
            />
            {t('admin.channels.repeatLimit')}
          </label>
          {limitOn && (
            <div className="flex flex-wrap items-end gap-2">
              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.repeatWindowDays')}</Label>
                <Input
                  type="number"
                  min={1}
                  max={365}
                  className="w-28"
                  value={windowDays}
                  onChange={(e) => setWindowDays(Number(e.target.value))}
                />
              </div>
              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.repeatMax')}</Label>
                <Input
                  type="number"
                  min={1}
                  className="w-28"
                  value={max}
                  onChange={(e) => setMax(Number(e.target.value))}
                />
              </div>
            </div>
          )}
          <p className="text-xs text-muted-foreground">{t('admin.channels.repeatLimitHint')}</p>
        </div>

        <div className="flex flex-col gap-2 border-t border-border pt-4">
          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.fallbackGroup')}</Label>
            <select
              className="h-9 rounded-md border border-border bg-transparent px-2"
              value={fallbackGroupId ?? ''}
              onChange={(e) => setFallbackGroupId(e.target.value || null)}
            >
              <option value="">{t('admin.channels.fallbackGroupNone')}</option>
              {(groups ?? []).map((group) => (
                <option key={group.id} value={group.id}>
                  {group.name} · {group.itemCount}
                </option>
              ))}
            </select>
          </div>
          <p className="text-xs text-muted-foreground">{t('admin.channels.fallbackGroupHint')}</p>
        </div>

        <div className="flex flex-col gap-2 border-t border-border pt-4">
          <h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
            {t('admin.channels.postChecks')}
          </h3>
          <div className="flex flex-wrap items-end gap-2">
            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.breakLimit')}</Label>
              <Input
                type="number"
                min={0}
                className="w-28"
                value={breakCap}
                onChange={(e) => setBreakCap(Number(e.target.value))}
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.genreShare')}</Label>
              <Input
                type="number"
                min={0}
                max={100}
                className="w-28"
                value={genreCap}
                onChange={(e) => setGenreCap(Number(e.target.value))}
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.fallbackShare')}</Label>
              <Input
                type="number"
                min={0}
                max={100}
                className="w-28"
                value={fallbackCap}
                onChange={(e) => setFallbackCap(Number(e.target.value))}
              />
            </div>
          </div>
          <p className="text-xs text-muted-foreground">{t('admin.channels.postChecksHint')}</p>
        </div>

        <div className="flex justify-end">
          <Button size="sm" disabled={save.isPending} onClick={() => save.mutate()}>
            {t('common.save')}
          </Button>
        </div>
      </div>
    </CollapsibleCard>
  )
}
