import { useMutation, useQuery } from '@tanstack/react-query'
import { Trash2 } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { listGroups } from '@/features/admin/groups/api'
import { listJunctions } from '@/features/admin/junctions/api'
import type {
  Daypart,
  OverflowPolicy,
  SlotBlockMode,
  SlotDto,
  SlotKind,
  SlotStrategyType,
} from '@/shared/api/types'
import { qk } from '@/shared/api/query-keys'
import { useApiError } from '@/shared/lib/use-api-error'
import { Button } from '@/shared/ui/button'
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/shared/ui/dialog'
import { Input } from '@/shared/ui/input'
import { Label } from '@/shared/ui/label'
import { createSlot, deleteSlot, toSlotBody, updateSlot, type SlotBody } from '../api'

const DAYPARTS: Daypart[] = ['Morning', 'Day', 'Prime', 'Night']
const SLOT_KINDS: SlotKind[] = ['Content', 'Repeat', 'SignOff']
const BLOCK_MODES: SlotBlockMode[] = ['Count', 'Duration', 'FillSlot']
const OVERFLOW: OverflowPolicy[] = ['ContinueNext', 'ExtendSlot', 'SkipIfNotFits']
const STRATEGIES: SlotStrategyType[] = ['Sequential', 'RandomWithCooldown', 'Fixed']
const SNAP_OPTIONS = [0, 5, 10, 15, 30]

/** Черновик слота: новый (layerId + предзаполненные время/день) либо существующий. */
export type SlotDraft = { layerId: string; slot: SlotDto | null; defaults?: Partial<SlotBody> }

function emptyBody(defaults?: Partial<SlotBody>): SlotBody {
  return {
    title: '',
    weekday: null,
    targetStart: '20:00:00',
    targetDurationMinutes: 60,
    daypart: 'Day',
    slotKind: 'Content',
    groupId: null,
    strategy: {
      type: 'Sequential',
      restartOnEnd: true,
      cooldownDays: 0,
      fallback: 'OldestFirst',
    },
    repeatSource: null,
    blockMode: 'FillSlot',
    blockValue: 1,
    overflowPolicy: 'ContinueNext',
    isAnchor: false,
    maxDriftMinutes: 5,
    snapToMinutes: null,
    junctionBetweenId: null,
    junctionAfterId: null,
    ...defaults,
  }
}

export function SlotInspector({
  draft,
  onClose,
  onChanged,
}: Readonly<{
  draft: SlotDraft
  onClose: () => void
  onChanged: () => void
}>) {
  const { t } = useTranslation()
  const [body, setBody] = useState<SlotBody>(() =>
    draft.slot ? toSlotBody(draft.slot) : emptyBody(draft.defaults),
  )

  useEffect(() => {
    setBody(draft.slot ? toSlotBody(draft.slot) : emptyBody(draft.defaults))
  }, [draft])

  const { data: groups } = useQuery({ queryKey: qk.groups.all, queryFn: listGroups })
  // Стыки общие для всех каналов — слот только выбирает, какой поставить.
  const { data: junctions } = useQuery({ queryKey: qk.junctions.all, queryFn: listJunctions })

  const onError = useApiError()

  const save = useMutation({
    mutationFn: async () => {
      if (draft.slot) await updateSlot(draft.slot.id, body)
      else await createSlot(draft.layerId, body)
    },
    onSuccess: () => {
      onChanged()
      onClose()
    },
    onError,
  })

  const remove = useMutation({
    mutationFn: () => deleteSlot(draft.slot!.id),
    onSuccess: () => {
      onChanged()
      onClose()
    },
    onError,
  })

  const patch = (part: Partial<SlotBody>) => setBody((prev) => ({ ...prev, ...part }))
  const isContent = body.slotKind === 'Content'

  return (
    // Отдельным окном, а не панелью под сеткой: форма длинная, и раньше она уезжала за нижний край,
    // а сетка — то, с чем её сверяют, — уходила из виду.
    <Dialog open onOpenChange={(next) => !next && onClose()}>
      <DialogContent className="flex max-h-[90vh] w-[calc(100%-2rem)] max-w-4xl flex-col">
        <DialogHeader>
          <DialogTitle>
            {draft.slot ? t('admin.channels.editSlot') : t('admin.channels.newSlot')}
          </DialogTitle>
        </DialogHeader>

        <div className="grid min-h-0 flex-1 gap-3 overflow-y-auto pr-1 text-sm sm:grid-cols-2">
          <div className="flex flex-col gap-1.5 sm:col-span-2">
            <Label>{t('admin.channels.slotTitle')}</Label>
            <Input value={body.title} onChange={(e) => patch({ title: e.target.value })} />
          </div>

          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.slotStart')}</Label>
            <Input
              type="time"
              value={body.targetStart.slice(0, 5)}
              onChange={(e) => patch({ targetStart: `${e.target.value}:00` })}
            />
          </div>
          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.slotDuration')}</Label>
            <Input
              type="number"
              min={1}
              value={body.targetDurationMinutes}
              onChange={(e) => patch({ targetDurationMinutes: Number(e.target.value) })}
            />
          </div>

          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.weekday')}</Label>
            <select
              className="h-9 rounded-md border border-border bg-transparent px-2"
              value={body.weekday ?? 'any'}
              onChange={(e) =>
                patch({ weekday: e.target.value === 'any' ? null : Number(e.target.value) })
              }
            >
              <option value="any">{t('admin.channels.everyDay')}</option>
              {[1, 2, 3, 4, 5, 6, 0].map((day) => (
                <option key={day} value={day}>
                  {t(`admin.channels.weekdays.${day}`)}
                </option>
              ))}
            </select>
          </div>

          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.daypart')}</Label>
            <select
              className="h-9 rounded-md border border-border bg-transparent px-2"
              value={body.daypart}
              onChange={(e) => patch({ daypart: e.target.value as Daypart })}
            >
              {DAYPARTS.map((value) => (
                <option key={value} value={value}>
                  {t(`admin.channels.dayparts.${value}`)}
                </option>
              ))}
            </select>
          </div>
          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.slotKind')}</Label>
            <select
              className="h-9 rounded-md border border-border bg-transparent px-2"
              value={body.slotKind}
              onChange={(e) => {
                const slotKind = e.target.value as SlotKind
                patch({
                  slotKind,
                  // Повтору нужен источник, конец вещания не берёт контент вовсе.
                  repeatSource:
                    slotKind === 'Repeat'
                      ? (body.repeatSource ?? {
                          daysAgo: 1,
                          time: '20:00:00',
                          durationMinutes: 90,
                        })
                      : null,
                })
              }}
            >
              {SLOT_KINDS.map((value) => (
                <option key={value} value={value}>
                  {t(`admin.channels.slotKinds.${value}`)}
                </option>
              ))}
            </select>
          </div>

          {isContent && (
            <>
              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.group')}</Label>
                <select
                  className="h-9 rounded-md border border-border bg-transparent px-2"
                  value={body.groupId ?? ''}
                  onChange={(e) => patch({ groupId: e.target.value || null })}
                >
                  <option value="">{t('admin.channels.pickGroup')}</option>
                  {(groups ?? []).map((group) => (
                    <option key={group.id} value={group.id}>
                      {group.name} · {group.itemCount}
                    </option>
                  ))}
                </select>
              </div>

              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.strategy')}</Label>
                <select
                  className="h-9 rounded-md border border-border bg-transparent px-2"
                  value={body.strategy?.type ?? 'Sequential'}
                  onChange={(e) =>
                    patch({
                      strategy: {
                        ...(body.strategy ?? {
                          restartOnEnd: true,
                          cooldownDays: 0,
                          fallback: 'OldestFirst',
                          type: 'Sequential',
                        }),
                        type: e.target.value as SlotStrategyType,
                      },
                    })
                  }
                >
                  {STRATEGIES.map((value) => (
                    <option key={value} value={value}>
                      {t(`admin.channels.strategies.${value}`)}
                    </option>
                  ))}
                </select>
              </div>

              {body.strategy?.type === 'RandomWithCooldown' && (
                <div className="flex flex-col gap-1.5">
                  <Label>{t('admin.channels.cooldownDays')}</Label>
                  <Input
                    type="number"
                    min={0}
                    value={body.strategy.cooldownDays}
                    onChange={(e) =>
                      patch({
                        strategy: { ...body.strategy!, cooldownDays: Number(e.target.value) },
                      })
                    }
                  />
                  <p className="text-xs text-muted-foreground">
                    {t('admin.channels.cooldownHint')}
                  </p>
                </div>
              )}

              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.blockMode')}</Label>
                <select
                  className="h-9 rounded-md border border-border bg-transparent px-2"
                  value={body.blockMode}
                  onChange={(e) => patch({ blockMode: e.target.value as SlotBlockMode })}
                >
                  {BLOCK_MODES.map((value) => (
                    <option key={value} value={value}>
                      {t(`admin.channels.blockModes.${value}`)}
                    </option>
                  ))}
                </select>
              </div>
              {body.blockMode !== 'FillSlot' && (
                <div className="flex flex-col gap-1.5">
                  <Label>{t('admin.channels.blockValue')}</Label>
                  <Input
                    type="number"
                    min={1}
                    value={body.blockValue}
                    onChange={(e) => patch({ blockValue: Number(e.target.value) })}
                  />
                </div>
              )}

              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.overflow')}</Label>
                <select
                  className="h-9 rounded-md border border-border bg-transparent px-2"
                  value={body.overflowPolicy}
                  onChange={(e) => patch({ overflowPolicy: e.target.value as OverflowPolicy })}
                >
                  {OVERFLOW.map((value) => (
                    <option key={value} value={value}>
                      {t(`admin.channels.overflows.${value}`)}
                    </option>
                  ))}
                </select>
                <p className="text-xs text-muted-foreground">{t('admin.channels.overflowHint')}</p>
              </div>
            </>
          )}

          {body.slotKind === 'Repeat' && body.repeatSource && (
            <div className="grid grid-cols-3 gap-2 sm:col-span-2">
              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.repeatDaysAgo')}</Label>
                <Input
                  type="number"
                  min={1}
                  value={body.repeatSource.daysAgo}
                  onChange={(e) =>
                    patch({
                      repeatSource: { ...body.repeatSource!, daysAgo: Number(e.target.value) },
                    })
                  }
                />
              </div>
              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.repeatTime')}</Label>
                <Input
                  type="time"
                  value={body.repeatSource.time.slice(0, 5)}
                  onChange={(e) =>
                    patch({ repeatSource: { ...body.repeatSource!, time: `${e.target.value}:00` } })
                  }
                />
              </div>
              <div className="flex flex-col gap-1.5">
                <Label>{t('admin.channels.repeatDuration')}</Label>
                <Input
                  type="number"
                  min={1}
                  value={body.repeatSource.durationMinutes}
                  onChange={(e) =>
                    patch({
                      repeatSource: {
                        ...body.repeatSource!,
                        durationMinutes: Number(e.target.value),
                      },
                    })
                  }
                />
              </div>
            </div>
          )}

          <div className="flex flex-wrap items-end gap-3 sm:col-span-2">
            <label className="flex items-center gap-2">
              <input
                type="checkbox"
                checked={body.isAnchor}
                onChange={(e) => patch({ isAnchor: e.target.checked })}
              />
              {t('admin.channels.anchor')}
            </label>
            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.maxDrift')}</Label>
              <Input
                type="number"
                min={0}
                className="w-24"
                value={body.maxDriftMinutes}
                onChange={(e) => patch({ maxDriftMinutes: Number(e.target.value) })}
              />
            </div>
            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.snap')}</Label>
              <select
                className="h-9 rounded-md border border-border bg-transparent px-2"
                value={body.snapToMinutes ?? 0}
                onChange={(e) =>
                  patch({
                    snapToMinutes: Number(e.target.value) === 0 ? null : Number(e.target.value),
                  })
                }
              >
                {SNAP_OPTIONS.map((value) => (
                  <option key={value} value={value}>
                    {value === 0 ? t('admin.channels.snapOff') : `${value}`}
                  </option>
                ))}
              </select>
            </div>
          </div>
          <p className="text-xs text-muted-foreground sm:col-span-2">
            {t('admin.channels.anchorHint')}
          </p>

          {/* Стыки: внутри слота — между единицами, после слота — на переходе к следующему. */}
          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.junctionBetween')}</Label>
            <select
              className="h-9 rounded-md border border-border bg-transparent px-2"
              value={body.junctionBetweenId ?? ''}
              onChange={(e) => patch({ junctionBetweenId: e.target.value || null })}
            >
              <option value="">{t('admin.channels.junctionDefault')}</option>
              {(junctions ?? []).map((junction) => (
                <option key={junction.id} value={junction.id}>
                  {junction.name}
                </option>
              ))}
            </select>
          </div>
          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.junctionAfter')}</Label>
            <select
              className="h-9 rounded-md border border-border bg-transparent px-2"
              value={body.junctionAfterId ?? ''}
              onChange={(e) => patch({ junctionAfterId: e.target.value || null })}
            >
              <option value="">{t('admin.channels.junctionDefault')}</option>
              {(junctions ?? []).map((junction) => (
                <option key={junction.id} value={junction.id}>
                  {junction.name}
                </option>
              ))}
            </select>
          </div>
        </div>

        <DialogFooter className="items-center justify-between">
          {draft.slot ? (
            <Button size="sm" variant="destructive" onClick={() => remove.mutate()}>
              <Trash2 className="h-4 w-4" />
              {t('common.delete')}
            </Button>
          ) : (
            <span />
          )}
          <div className="flex items-center gap-2">
            <Button size="sm" variant="outline" onClick={onClose}>
              {t('common.cancel')}
            </Button>
            <Button size="sm" disabled={save.isPending} onClick={() => save.mutate()}>
              {t('common.save')}
            </Button>
          </div>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
