import { useMutation } from '@tanstack/react-query'
import { AlertTriangle, Copy, Download, Sparkles, Upload } from 'lucide-react'
import { useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import type { GridConfig } from '@/shared/api/types'
import { Button } from '@/shared/ui/button'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/shared/ui/dialog'
import { Input } from '@/shared/ui/input'
import { Label } from '@/shared/ui/label'
import { toast } from '@/shared/ui/toast-store'
import { buildGridPrompt, exportGrid, importGrid } from '../api'

type Tab = 'export' | 'import' | 'ai'

const FIELD = 'w-full rounded-sm border border-border bg-transparent px-3 py-2 text-sm'

const TABS: Tab[] = ['export', 'import', 'ai']

/** Файл конфигурации в человекочитаемом виде — его правят руками и отдают модели. */
function download(channelName: string, config: GridConfig) {
  const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' })
  const url = URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = `${channelName || 'grid'}.telewave.json`
  link.click()
  URL.revokeObjectURL(url)
}

/**
 * Обмен конфигурацией сетки: выгрузить файлом, загрузить чужой файл, собрать запрос к ИИ.
 *
 * Запрос к модели никуда не отправляется: ключей внешних сервисов проект не хранит, и заводить их
 * ради одной кнопки не нужно. Админ копирует текст в ту модель, которой пользуется, и приносит
 * ответ назад той же вкладкой импорта — формат у запроса и у импорта один.
 */
export function GridTransferDialog({
  channelId,
  channelName,
  onClose,
  onImported,
  onError,
}: Readonly<{
  channelId: string
  channelName: string
  onClose: () => void
  onImported: () => void
  onError: (error: unknown) => void
}>) {
  const { t } = useTranslation()
  const [tab, setTab] = useState<Tab>('export')

  const [text, setText] = useState('')
  const [replace, setReplace] = useState(true)
  const [warnings, setWarnings] = useState<string[]>([])
  const fileInput = useRef<HTMLInputElement>(null)

  const [references, setReferences] = useState('')
  const [notes, setNotes] = useState('')
  const [prompt, setPrompt] = useState('')

  const exportMutation = useMutation({
    mutationFn: () => exportGrid(channelId),
    onSuccess: (config) => {
      download(channelName, config)
      toast.success(t('admin.channels.transfer.exported'))
    },
    onError,
  })

  const importMutation = useMutation({
    mutationFn: () => {
      // Разбор здесь, а не в мутации-обёртке: битый JSON — самая частая ошибка, и сказать о ней
      // надо строкой в диалоге, а не общим «не удалось сохранить».
      const config = JSON.parse(text) as GridConfig
      return importGrid(channelId, config, replace)
    },
    onSuccess: (result) => {
      setWarnings(result.warnings)
      toast.success(
        t('admin.channels.transfer.imported', {
          slots: result.slots,
          skipped: result.skipped,
        }),
      )
      // Заведённые группы упоминаем отдельно: файл от модели меняет не только сетку, и узнать
      // об этом из общего «создано слотов» нельзя.
      if (result.groups > 0 || result.collections > 0)
        toast.success(
          t('admin.channels.transfer.importedLibrary', {
            groups: result.groups,
            collections: result.collections,
          }),
        )
      onImported()
    },
    onError: (error: unknown) => {
      if (error instanceof SyntaxError) {
        toast.error(t('admin.channels.transfer.badJson'))
        return
      }
      onError(error)
    },
  })

  const promptMutation = useMutation({
    mutationFn: () =>
      buildGridPrompt(
        channelId,
        references
          .split(/[\n,]/)
          .map((r) => r.trim())
          .filter(Boolean),
        notes,
      ),
    onSuccess: (result) => setPrompt(result.prompt),
    onError,
  })

  const copyPrompt = async () => {
    await navigator.clipboard.writeText(prompt)
    toast.success(t('admin.channels.transfer.copied'))
  }

  const pickFile = (file: File | undefined) => {
    if (!file) return
    file
      .text()
      .then((content) => {
        setText(content)
        setWarnings([])
      })
      .catch(onError)
  }

  return (
    <Dialog open onOpenChange={onClose}>
      <DialogContent className="max-w-3xl">
        <DialogHeader>
          <DialogTitle>{t('admin.channels.transfer.title')}</DialogTitle>
          <DialogDescription>{t('admin.channels.transfer.hint')}</DialogDescription>
        </DialogHeader>

        <div className="flex gap-1 border-b border-border">
          {TABS.map((item) => (
            <button
              key={item}
              type="button"
              onClick={() => setTab(item)}
              className={`-mb-px border-b-2 px-3 py-1.5 text-sm ${
                tab === item
                  ? 'border-primary text-foreground'
                  : 'border-transparent text-muted-foreground hover:text-foreground'
              }`}
            >
              {t(`admin.channels.transfer.tabs.${item}`)}
            </button>
          ))}
        </div>

        {tab === 'export' && (
          <div className="flex flex-col gap-3 text-sm">
            <p className="text-muted-foreground">{t('admin.channels.transfer.exportHint')}</p>
            <div>
              <Button
                size="sm"
                onClick={() => exportMutation.mutate()}
                disabled={exportMutation.isPending}
              >
                <Download className="h-4 w-4" />
                {t('admin.channels.transfer.exportAction')}
              </Button>
            </div>
          </div>
        )}

        {tab === 'import' && (
          <div className="flex flex-col gap-3 text-sm">
            <p className="text-muted-foreground">{t('admin.channels.transfer.importHint')}</p>

            <div className="flex flex-wrap items-center gap-2">
              <input
                ref={fileInput}
                type="file"
                accept="application/json,.json"
                className="hidden"
                onChange={(e) => pickFile(e.target.files?.[0])}
              />
              <Button size="sm" variant="outline" onClick={() => fileInput.current?.click()}>
                <Upload className="h-4 w-4" />
                {t('admin.channels.transfer.pickFile')}
              </Button>
              <label className="flex items-center gap-2">
                <input
                  type="checkbox"
                  checked={replace}
                  onChange={(e) => setReplace(e.target.checked)}
                />
                {t('admin.channels.transfer.replace')}
              </label>
            </div>

            <textarea
              rows={12}
              className={FIELD + ' font-mono text-xs'}
              placeholder={t('admin.channels.transfer.pastePlaceholder')}
              value={text}
              onChange={(e) => setText(e.target.value)}
            />

            {warnings.length > 0 && (
              <div className="flex flex-col gap-1 rounded border border-amber-500/40 bg-amber-500/10 p-2 text-xs">
                <span className="flex items-center gap-1.5 font-medium text-amber-500">
                  <AlertTriangle className="h-3.5 w-3.5" />
                  {t('admin.channels.transfer.warnings')}
                </span>
                {warnings.map((warning) => (
                  <span key={warning} className="text-muted-foreground">
                    {warning}
                  </span>
                ))}
              </div>
            )}

            <div>
              <Button
                size="sm"
                disabled={!text.trim() || importMutation.isPending}
                onClick={() => importMutation.mutate()}
              >
                <Upload className="h-4 w-4" />
                {t('admin.channels.transfer.importAction')}
              </Button>
            </div>
          </div>
        )}

        {tab === 'ai' && (
          <div className="flex flex-col gap-3 text-sm">
            <p className="text-muted-foreground">{t('admin.channels.transfer.aiHint')}</p>

            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.transfer.references')}</Label>
              <Input
                value={references}
                placeholder={t('admin.channels.transfer.referencesPlaceholder')}
                onChange={(e) => setReferences(e.target.value)}
              />
              <span className="text-xs text-muted-foreground">
                {t('admin.channels.transfer.referencesHint')}
              </span>
            </div>

            <div className="flex flex-col gap-1.5">
              <Label>{t('admin.channels.transfer.notes')}</Label>
              <textarea
                rows={3}
                className={FIELD}
                value={notes}
                placeholder={t('admin.channels.transfer.notesPlaceholder')}
                onChange={(e) => setNotes(e.target.value)}
              />
            </div>

            <div className="flex flex-wrap items-center gap-2">
              <Button
                size="sm"
                onClick={() => promptMutation.mutate()}
                disabled={promptMutation.isPending}
              >
                <Sparkles className="h-4 w-4" />
                {t('admin.channels.transfer.buildPrompt')}
              </Button>
              {prompt && (
                <Button size="sm" variant="outline" onClick={copyPrompt}>
                  <Copy className="h-4 w-4" />
                  {t('admin.channels.transfer.copyPrompt')}
                </Button>
              )}
            </div>

            {prompt && (
              <>
                <textarea
                  rows={14}
                  readOnly
                  className={FIELD + ' font-mono text-xs'}
                  value={prompt}
                  onFocus={(e) => e.currentTarget.select()}
                />
                <p className="text-xs text-muted-foreground">
                  {t('admin.channels.transfer.aiNext')}
                </p>
              </>
            )}
          </div>
        )}

        <DialogFooter>
          <Button size="sm" variant="ghost" onClick={onClose}>
            {t('common.close')}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
