import { useMutation } from '@tanstack/react-query'
import { ChevronRight, Merge, Split, Trash2 } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { formatClock } from '@/features/admin/interstitials/format'
import type {
  BumperTemplateDto,
  GroupSummaryDto,
  JunctionElementDto,
  JunctionElementKind,
  JunctionTemplateDto,
} from '@/shared/api/types'
import { cn } from '@/shared/lib/cn'
import { Button } from '@/shared/ui/button'
import { Input } from '@/shared/ui/input'
import {
  addJunctionElement,
  deleteJunction,
  reorderJunction,
  updateJunction,
  type JunctionElementOrder,
} from '../api'
import { choicePercent, KIND_COLORS, stepSeconds, toSteps, type ChainStep } from '../lib'
import { JunctionElementDialog } from './JunctionElementDialog'

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

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

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

/** Условия врезки одной строкой — иначе их не видно, не открыв каждую. */
function conditionsHint(element: JunctionElementDto, t: Translate) {
  const parts: string[] = []
  const c = element.conditions
  if (c?.onlyOnElementChange) parts.push(t('admin.junctions.badgeOnChange'))
  if (c && c.chance < 100) parts.push(`${c.chance}%`)
  if (c && c.minMinutesBetween > 0)
    parts.push(t('admin.junctions.badgeInterval', { minutes: c.minMinutesBetween }))
  if (c?.timeWindow) parts.push(`${c.timeWindow.from.slice(0, 5)}–${c.timeWindow.to.slice(0, 5)}`)
  if (c && c.nearHourMinutes > 0)
    parts.push(t('admin.junctions.badgeNearHour', { minutes: c.nearHourMinutes }))
  if (c?.dayparts?.length)
    parts.push(c.dayparts.map((d) => t(`admin.channels.dayparts.${d}`)).join('/'))
  return parts.join(' · ')
}

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

  const steps = toSteps(junction.elements)
  const estimates = steps.map((step) => stepSeconds(step, groups, bumpers))
  const total = estimates.reduce((sum, e) => sum + e.seconds, 0)
  const exact = estimates.every((e) => e.exact)
  const overCap = junction.maxTotalSeconds != null && total > junction.maxTotalSeconds

  const saveHeader = useMutation({
    mutationFn: (next: { name: string; maxTotalSeconds: number | null }) =>
      updateJunction(junction.id, next.name, next.maxTotalSeconds),
    onSuccess: () => {
      setName(null)
      setMaxTotal(null)
      onChanged()
    },
    onError,
  })
  const removeJunction = useMutation({
    mutationFn: () => deleteJunction(junction.id),
    onSuccess: onChanged,
    onError,
  })
  const addElement = useMutation({
    mutationFn: (kind: JunctionElementKind) => addJunctionElement(junction.id, kind),
    onSuccess: onChanged,
    onError,
  })
  const reorder = useMutation({
    mutationFn: (order: JunctionElementOrder[]) => reorderJunction(junction.id, order),
    onSuccess: onChanged,
    onError,
  })

  const flat = (): JunctionElementOrder[] =>
    steps.flatMap((step) => step.elements.map((e) => ({ elementId: e.id, choiceKey: e.choiceKey })))

  /** Перетаскивание: врезка встаёт перед целевым звеном, метка развилки сохраняется. */
  const dropOn = (targetStep: ChainStep) => {
    if (!dragged) return
    const order = flat().filter((o) => o.elementId !== dragged)
    const draggedItem = flat().find((o) => o.elementId === dragged)
    const at = order.findIndex((o) => o.elementId === targetStep.elements[0].id)
    if (draggedItem) order.splice(at < 0 ? order.length : at, 0, draggedItem)
    setDragged(null)
    reorder.mutate(order)
  }

  /** Объединить с предыдущим звеном в развилку — одна кнопка вместо отдельного редактора групп. */
  const mergeWithPrevious = (index: number) => {
    const previous = steps[index - 1]
    const key = previous.choiceKey ?? `fork-${previous.elements[0].id.slice(0, 8)}`
    const order = flat().map((o) =>
      previous.elements.some((e) => e.id === o.elementId) ||
      steps[index].elements.some((e) => e.id === o.elementId)
        ? { ...o, choiceKey: key }
        : o,
    )
    reorder.mutate(order)
  }

  const splitOut = (element: JunctionElementDto) => {
    const order = flat().map((o) => (o.elementId === element.id ? { ...o, choiceKey: null } : o))
    reorder.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
              ? saveHeader.mutate({
                  name: name.trim(),
                  maxTotalSeconds: junction.maxTotalSeconds,
                })
              : setName(null)
          }
        />
        <label className="flex items-center gap-1 text-xs text-muted-foreground">
          {t('admin.junctions.maxTotal')}
          <Input
            className="h-8 w-20"
            type="number"
            min={0}
            placeholder="—"
            value={maxTotal ?? junction.maxTotalSeconds ?? ''}
            onChange={(e) => setMaxTotal(e.target.value)}
            onBlur={() => {
              if (maxTotal === null) return
              const parsed = Number(maxTotal)
              saveHeader.mutate({
                name: junction.name,
                maxTotalSeconds: maxTotal.trim() === '' || parsed <= 0 ? null : Math.round(parsed),
              })
            }}
          />
        </label>
        <select
          className="h-8 rounded-md border border-border bg-transparent px-2 text-sm"
          value=""
          onChange={(e) =>
            e.target.value && addElement.mutate(e.target.value as JunctionElementKind)
          }
        >
          <option value="">{t('admin.junctions.addElement')}</option>
          {ADDABLE.map((kind) => (
            <option key={kind} value={kind}>
              {t(`admin.junctions.kinds.${kind}`)}
            </option>
          ))}
        </select>
        {junction.channelUsageCount > 0 && (
          <span className="text-xs text-muted-foreground">
            {t('admin.junctions.usedInChannels', { count: junction.channelUsageCount })}
          </span>
        )}
        <span
          className={cn('ml-auto text-xs', overCap ? 'text-destructive' : 'text-muted-foreground')}
        >
          {exact ? '' : '≈ '}
          {formatClock(total)}
          {junction.maxTotalSeconds != null && ` / ${formatClock(junction.maxTotalSeconds)}`}
        </span>
        <Button
          size="sm"
          variant="ghost"
          disabled={junction.channelUsageCount > 0}
          title={junction.channelUsageCount > 0 ? t('admin.junctions.cannotDeleteUsed') : undefined}
          onClick={() => removeJunction.mutate()}
        >
          <Trash2 className="h-4 w-4" />
        </Button>
      </div>

      {/* Цепочка: что играет между концом одной программы и началом следующей. */}
      <div className="flex flex-wrap items-stretch gap-1 text-xs">
        <span className="self-center rounded border border-border px-2 py-1 uppercase text-muted-foreground">
          {t('admin.junctions.from')}
        </span>
        {steps.length === 0 && (
          <>
            <ChevronRight className="h-3 w-3 self-center text-muted-foreground" />
            <span className="self-center text-muted-foreground">{t('admin.junctions.empty')}</span>
          </>
        )}
        {steps.map((step, index) => (
          <div key={step.key} className="flex items-stretch gap-1">
            <ChevronRight className="h-3 w-3 shrink-0 self-center text-muted-foreground" />
            <div
              onDragOver={(e) => e.preventDefault()}
              onDrop={() => dropOn(step)}
              className={cn(
                'flex flex-col gap-1 rounded',
                step.elements.length > 1 && 'border border-dashed border-primary/50 p-1',
              )}
            >
              {step.elements.length > 1 && (
                <span className="px-1 text-[10px] uppercase tracking-wide text-primary/80">
                  {t('admin.junctions.fork')}
                </span>
              )}
              {step.elements.map((element) => (
                <div key={element.id} className="flex items-center gap-1">
                  <button
                    type="button"
                    draggable
                    onDragStart={() => setDragged(element.id)}
                    onClick={() => setEditing(element)}
                    className={cn(
                      'flex cursor-grab flex-col items-start rounded border border-border px-2 py-1 text-left hover:border-primary',
                      element.isRequired && 'border-primary/70',
                    )}
                  >
                    <span>
                      {step.elements.length > 1 && (
                        <span className="mr-1 text-primary/80">
                          {choicePercent(step, element)}%
                        </span>
                      )}
                      {t(`admin.junctions.kinds.${element.kind}`)}
                      {elementSuffix(element, t)}
                      {element.isRequired && ' *'}
                    </span>
                    {conditionsHint(element, t) && (
                      <span className="text-[10px] text-muted-foreground">
                        {conditionsHint(element, t)}
                      </span>
                    )}
                  </button>
                  {/* Развилка собирается тут же: отдельный редактор групп ради двух кнопок не нужен. */}
                  {step.elements.length > 1 ? (
                    <Button
                      size="sm"
                      variant="ghost"
                      className="h-6 w-6 p-0"
                      title={t('admin.junctions.splitOut')}
                      onClick={() => splitOut(element)}
                    >
                      <Split className="h-3 w-3" />
                    </Button>
                  ) : (
                    index > 0 && (
                      <Button
                        size="sm"
                        variant="ghost"
                        className="h-6 w-6 p-0"
                        title={t('admin.junctions.mergeIntoFork')}
                        onClick={() => mergeWithPrevious(index)}
                      >
                        <Merge className="h-3 w-3" />
                      </Button>
                    )
                  )}
                </div>
              ))}
            </div>
          </div>
        ))}
        <ChevronRight className="h-3 w-3 self-center text-muted-foreground" />
        <span className="self-center rounded border border-border px-2 py-1 uppercase text-muted-foreground">
          {t('admin.junctions.to')}
        </span>
      </div>

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

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