import { useMutation, useQuery } from '@tanstack/react-query'
import { ChevronRight, Plus, Trash2 } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { listGroups } from '@/features/admin/groups/api'
import { formatClock } from '@/features/admin/interstitials/format'
import type {
  ChannelDto,
  GroupSummaryDto,
  JunctionElementDto,
  JunctionElementKind,
  JunctionTemplateDto,
  ScheduleTemplateDto,
} from '@/shared/api/types'
import { qk } from '@/shared/api/query-keys'
import { Button } from '@/shared/ui/button'
import { Input } from '@/shared/ui/input'
import { Label } from '@/shared/ui/label'
import { cn } from '@/shared/lib/cn'
import {
  addJunctionElement,
  createJunction,
  deleteJunction,
  listJunctions,
  renameJunction,
  reorderJunction,
  updateTemplate,
} from '../api'
import { CollapsibleCard } from './CollapsibleCard'
import { JunctionElementDialog } from './JunctionElementDialog'

/** Заставка без загруженного звука синтезируется фиксированной длины — та же цифра, что на сервере. */
const DEFAULT_BUMPER_SECONDS = 8

const KIND_COLORS: Record<JunctionElementKind, string> = {
  Ad: 'bg-amber-500/70',
  Promo: 'bg-sky-500/70',
  Bumper: 'bg-violet-500/70',
  Filler: 'bg-muted-foreground/40',
}

type Translate = ReturnType<typeof useTranslation>['t']

/** Что уточняет подпись врезки: имя блока заставки либо объём («×3» / «×5 мин»). */
function elementSuffix(element: JunctionElementDto, t: Translate) {
  if (element.kind === 'Bumper')
    return element.bumperTemplateName ? ` · ${element.bumperTemplateName}` : ''

  const units = element.amountMode === 'Duration' ? t('admin.channels.minutesShort') : ''
  return ` ×${element.amountValue}${units}`
}

/** Подсказка сегмента линейки: вид врезки и её оценочная длительность. */
function elementTitle(element: JunctionElementDto, seconds: number, t: Translate) {
  const kind = t(`admin.channels.junctionKinds.${element.kind}`)
  return `${kind} · ${formatClock(seconds)}`
}

/**
 * Прикидка длины врезки для линейки. По длительности — точная, по количеству — среднее единицы
 * группы: в смешанной группе «одна единица» это то ли ролик, то ли блок, поэтому число заведомо
 * приблизительное и помечается как оценка.
 */
function estimateSeconds(
  element: JunctionElementDto,
  groups: GroupSummaryDto[] | undefined,
  channel: ChannelDto,
): { seconds: number; exact: boolean } {
  if (element.kind === 'Bumper') {
    const template = channel.bumperTemplates.find((b) => b.id === element.bumperTemplateId)
    return { seconds: template?.audioDurationSeconds ?? DEFAULT_BUMPER_SECONDS, exact: true }
  }
  if (element.amountMode === 'Duration') return { seconds: element.amountValue * 60, exact: true }

  const group = groups?.find((g) => g.id === element.groupId)
  if (!group || group.unitCount === 0) return { seconds: 0, exact: false }
  return {
    seconds: (element.amountValue * group.totalDurationSeconds) / group.unitCount,
    exact: false,
  }
}

export function JunctionsCard({
  channel,
  template,
  bare,
  onChanged,
  onError,
}: Readonly<{
  channel: ChannelDto
  template: ScheduleTemplateDto | undefined
  bare?: boolean
  onChanged: () => void
  onError: (error: unknown) => void
}>) {
  const { t } = useTranslation()
  const [newName, setNewName] = useState('')

  const { data: junctions } = useQuery({
    queryKey: qk.channels.junctions(channel.id),
    queryFn: () => listJunctions(channel.id),
  })
  const { data: groups } = useQuery({ queryKey: qk.groups.all, queryFn: listGroups })

  const createMutation = useMutation({
    mutationFn: () => createJunction(channel.id, newName.trim()),
    onSuccess: () => {
      setNewName('')
      onChanged()
    },
    onError,
  })

  const defaultMutation = useMutation({
    mutationFn: (junctionId: string | null) =>
      updateTemplate(template!.id, {
        name: template!.name,
        fallbackGroupId: template!.fallbackGroupId,
        defaultJunctionId: junctionId,
        rules: template!.rules,
      }),
    onSuccess: onChanged,
    onError,
  })

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

        {template && (
          <div className="flex flex-col gap-1.5">
            <Label>{t('admin.channels.defaultJunction')}</Label>
            <select
              className="h-9 max-w-xs rounded-md border border-border bg-transparent px-2 text-sm"
              value={template.defaultJunctionId ?? ''}
              onChange={(e) => defaultMutation.mutate(e.target.value || null)}
            >
              <option value="">{t('admin.channels.noJunction')}</option>
              {(junctions ?? []).map((junction) => (
                <option key={junction.id} value={junction.id}>
                  {junction.name}
                </option>
              ))}
            </select>
          </div>
        )}

        {(junctions ?? []).map((junction) => (
          <JunctionChain
            key={junction.id}
            junction={junction}
            channel={channel}
            groups={groups}
            onChanged={onChanged}
            onError={onError}
          />
        ))}

        <div className="flex max-w-md gap-2">
          <Input
            placeholder={t('admin.channels.newJunctionName')}
            value={newName}
            maxLength={128}
            onChange={(e) => setNewName(e.target.value)}
          />
          <Button
            size="sm"
            variant="outline"
            disabled={!newName.trim() || createMutation.isPending}
            onClick={() => createMutation.mutate()}
          >
            <Plus className="h-4 w-4" /> {t('common.create')}
          </Button>
        </div>
      </div>
    </CollapsibleCard>
  )
}

const ADDABLE: JunctionElementKind[] = ['Ad', 'Promo', 'Bumper', 'Filler']

function JunctionChain({
  junction,
  channel,
  groups,
  onChanged,
  onError,
}: Readonly<{
  junction: JunctionTemplateDto
  channel: ChannelDto
  groups: GroupSummaryDto[] | undefined
  onChanged: () => void
  onError: (error: unknown) => void
}>) {
  const { t } = useTranslation()
  const [name, setName] = useState<string | null>(null)
  const [dragged, setDragged] = useState<string | null>(null)
  const [editing, setEditing] = useState<JunctionElementDto | null>(null)

  const renameMutation = useMutation({
    mutationFn: (value: string) => renameJunction(junction.id, value),
    onSuccess: () => {
      setName(null)
      onChanged()
    },
    onError,
  })
  const deleteMutation = useMutation({
    mutationFn: () => deleteJunction(junction.id),
    onSuccess: onChanged,
    onError,
  })
  const addMutation = useMutation({
    mutationFn: (kind: JunctionElementKind) => addJunctionElement(junction.id, kind),
    onSuccess: onChanged,
    onError,
  })
  const reorderMutation = useMutation({
    mutationFn: (order: string[]) => reorderJunction(junction.id, order),
    onSuccess: onChanged,
    onError,
  })

  const elements = [...junction.elements].sort((a, b) => a.position - b.position)
  const estimates = elements.map((element) => estimateSeconds(element, groups, channel))
  const total = estimates.reduce((sum, e) => sum + e.seconds, 0)
  const exact = estimates.every((e) => e.exact)

  const dropOn = (targetId: string) => {
    if (!dragged || dragged === targetId) return
    const order = elements.map((e) => e.id).filter((id) => id !== dragged)
    order.splice(order.indexOf(targetId), 0, dragged)
    setDragged(null)
    reorderMutation.mutate(order)
  }

  return (
    <div className="crt-panel flex flex-col gap-2 rounded-md p-3">
      <div className="flex flex-wrap items-center gap-2">
        <Input
          className="h-8 max-w-56"
          value={name ?? junction.name}
          maxLength={128}
          onChange={(e) => setName(e.target.value)}
          onBlur={() =>
            name !== null && name.trim() && name !== junction.name
              ? renameMutation.mutate(name.trim())
              : setName(null)
          }
        />
        <select
          className="h-8 rounded-md border border-border bg-transparent px-2 text-sm"
          value=""
          onChange={(e) =>
            e.target.value && addMutation.mutate(e.target.value as JunctionElementKind)
          }
        >
          <option value="">{t('admin.channels.addJunctionElement')}</option>
          {ADDABLE.map((kind) => (
            <option key={kind} value={kind}>
              {t(`admin.channels.junctionKinds.${kind}`)}
            </option>
          ))}
        </select>
        <span className="ml-auto text-xs text-muted-foreground">
          {exact ? '' : '≈ '}
          {formatClock(total)}
        </span>
        <Button size="sm" variant="ghost" onClick={() => deleteMutation.mutate()}>
          <Trash2 className="h-4 w-4" />
        </Button>
      </div>

      {/* Цепочка: что играет между концом одной программы и началом следующей. */}
      <div className="flex flex-wrap items-center gap-1 text-xs">
        <span className="rounded border border-border px-2 py-1 uppercase text-muted-foreground">
          {t('admin.channels.junctionFrom')}
        </span>
        {elements.length === 0 && (
          <>
            <ChevronRight className="h-3 w-3 text-muted-foreground" />
            <span className="text-muted-foreground">{t('admin.channels.junctionEmpty')}</span>
          </>
        )}
        {elements.map((element) => (
          <span key={element.id} className="flex items-center gap-1">
            <ChevronRight className="h-3 w-3 shrink-0 text-muted-foreground" />
            <button
              type="button"
              draggable
              onDragStart={() => setDragged(element.id)}
              onDragOver={(e) => e.preventDefault()}
              onDrop={() => dropOn(element.id)}
              onClick={() => setEditing(element)}
              className={cn(
                'cursor-grab rounded border border-border px-2 py-1 hover:border-primary',
                element.isRequired && 'border-primary/70',
              )}
            >
              {t(`admin.channels.junctionKinds.${element.kind}`)}
              {elementSuffix(element, t)}
              {element.isRequired && ' *'}
            </button>
          </span>
        ))}
        <ChevronRight className="h-3 w-3 text-muted-foreground" />
        <span className="rounded border border-border px-2 py-1 uppercase text-muted-foreground">
          {t('admin.channels.junctionTo')}
        </span>
      </div>

      {/* Линейка: доля каждой врезки в стыке. Пустые (без группы) в неё не попадают. */}
      {total > 0 && (
        <div className="flex h-2 overflow-hidden rounded-full bg-muted/40">
          {elements.map((element, index) => (
            <div
              key={element.id}
              className={KIND_COLORS[element.kind]}
              style={{ width: `${(estimates[index].seconds / total) * 100}%` }}
              title={elementTitle(element, estimates[index].seconds, t)}
            />
          ))}
        </div>
      )}

      {editing && (
        <JunctionElementDialog
          junctionId={junction.id}
          element={editing}
          bumperTemplates={channel.bumperTemplates}
          onClose={() => setEditing(null)}
          onChanged={onChanged}
          onError={onError}
        />
      )}
    </div>
  )
}
