import { useState, useEffect, useCallback } from 'react'
import {
  KeyRound, Save, RefreshCw, Check, X, AlertCircle,
  ChevronDown, ChevronRight, Trash2, Plus, Eye, EyeOff,
  Lock, Unlock, Info, HardDriveDownload, Zap, Terminal,
} from 'lucide-react'
import { api, type TTLockConfig, type RoomLockMapping, type Workstation } from '../lib/api'
import { useAuth } from '../contexts/AuthContext'
import { cn } from '../lib/utils'
import type { Room } from '../types'

// ── Helpers ───────────────────────────────────────────────────────────────────

function Section({ title, children, defaultOpen = true }: {
  title: string; children: React.ReactNode; defaultOpen?: boolean
}) {
  const [open, setOpen] = useState(defaultOpen)
  return (
    <div className="border border-slate-200 dark:border-slate-700 rounded-xl overflow-hidden">
      <button
        onClick={() => setOpen(o => !o)}
        className="w-full flex items-center justify-between px-6 py-4 bg-slate-50 dark:bg-slate-800/50 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors text-left"
      >
        <span className="font-semibold text-slate-800 dark:text-slate-200">{title}</span>
        {open
          ? <ChevronDown size={16} className="text-slate-500" />
          : <ChevronRight size={16} className="text-slate-500" />}
      </button>
      {open && <div className="p-6 bg-white dark:bg-slate-900">{children}</div>}
    </div>
  )
}

function PasswordInput({ value, onChange, placeholder }: {
  value: string; onChange: (v: string) => void; placeholder?: string
}) {
  const [show, setShow] = useState(false)
  return (
    <div className="relative">
      <input
        type={show ? 'text' : 'password'}
        value={value}
        onChange={e => onChange(e.target.value)}
        placeholder={placeholder}
        className="input pr-10 w-full"
      />
      <button
        type="button"
        onClick={() => setShow(s => !s)}
        className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600"
      >
        {show ? <EyeOff size={15} /> : <Eye size={15} />}
      </button>
    </div>
  )
}

// ── Hint box ──────────────────────────────────────────────────────────────────
function Hint({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex gap-2 p-3 rounded-lg bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 text-xs">
      <Info size={14} className="shrink-0 mt-0.5" />
      <div>{children}</div>
    </div>
  )
}

// ── Sector Picker ─────────────────────────────────────────────────────────────

function SectorPicker({ value, onChange }: {
  value: string
  onChange: (v: string) => void
}) {
  // Parse comma-separated string into a Set of numbers
  const selected = new Set(
    value.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n) && n >= 1 && n <= 16)
  )

  const toggle = (n: number) => {
    const next = new Set(selected)
    if (next.has(n)) {
      next.delete(n)
    } else {
      next.add(n)
    }
    // Sort numerically and join
    const sorted = Array.from(next).sort((a, b) => a - b)
    onChange(sorted.join(','))
  }

  return (
    <div>
      <div className="flex flex-wrap gap-2 mt-1">
        {Array.from({ length: 16 }, (_, i) => i + 1).map(n => (
          <button
            key={n}
            type="button"
            onClick={() => toggle(n)}
            title={`Сектор ${n}`}
            className={cn(
              'w-9 h-9 rounded-full text-sm font-semibold transition-colors border-2',
              selected.has(n)
                ? 'bg-brand-600 border-brand-600 text-white hover:bg-brand-700 hover:border-brand-700'
                : 'bg-white dark:bg-slate-800 border-slate-300 dark:border-slate-600 text-slate-500 dark:text-slate-400 hover:border-brand-400 hover:text-brand-600',
            )}
          >
            {n}
          </button>
        ))}
      </div>
      <p className="text-xs text-slate-500 mt-2">
        Выбрано: <code className="bg-slate-100 dark:bg-slate-800 px-1 rounded font-mono">{value || '(нет)'}</code>
        {' — '}секторы Mifare-карты, которые использует TTHotel. Обычно 1–10.
      </p>
    </div>
  )
}

// ── DLL error note ────────────────────────────────────────────────────────────
function isDllEntryError(msg: string): boolean {
  return msg.includes('точку входа') || msg.toLowerCase().includes('entrypoint') || msg.toLowerCase().includes('entry point')
}

// ── Main Page ─────────────────────────────────────────────────────────────────

export function TTLockPage() {
  const { user } = useAuth()
  const slug = user?.hotelSlug ?? ''

  const [config, setConfig]         = useState<TTLockConfig | null>(null)
  const [mappings, setMappings]     = useState<RoomLockMapping[]>([])
  const [rooms, setRooms]           = useState<Room[]>([])
  const [workstations, setWorkstations] = useState<Workstation[]>([])
  const [loading, setLoading]       = useState(true)
  const [saving, setSaving]         = useState(false)
  const [error, setError]           = useState<string | null>(null)
  const [success, setSuccess]       = useState<string | null>(null)

  // Форма настроек
  const [isEnabled, setIsEnabled]       = useState(false)
  const [clientId, setClientId]         = useState('')
  const [clientSecret, setClientSecret] = useState('')
  const [cardSectors, setCardSectors]   = useState('1,2,3,4,5,6,7,8,9,10')

  // Per-workstation COM port state
  const [wsComPorts, setWsComPorts]   = useState<Record<string, string>>({})
  const [wsSaving, setWsSaving]       = useState<Record<string, boolean>>({})
  const [wsTesting, setWsTesting]     = useState<Record<string, boolean>>({})

  // Per-workstation port list state
  const [wsPorts, setWsPorts]               = useState<Record<string, { port: string; description?: string }[]>>({})
  const [wsPortsLoading, setWsPortsLoading] = useState<Record<string, boolean>>({})

  // Форма привязки замков
  const [addRoomId, setAddRoomId]   = useState('')
  const [addLockMac, setAddLockMac] = useState('')
  const [addLockName, setAddLockName] = useState('')
  const [addLoading, setAddLoading] = useState(false)

  const showSuccess = (msg: string) => {
    setSuccess(msg); setTimeout(() => setSuccess(null), 3500)
  }

  const load = useCallback(async () => {
    if (!slug) return
    setLoading(true)
    try {
      const [cfg, maps, roomList, wsList] = await Promise.all([
        api.ttlock.getConfig(slug),
        api.ttlock.getRoomLocks(slug),
        api.rooms.list(slug),
        api.workstations.list(slug),
      ])
      setConfig(cfg)
      setIsEnabled(cfg.isEnabled)
      setClientId(cfg.clientId)
      setCardSectors(cfg.cardSectors || '1,2,3,4,5,6,7,8,9,10')
      setMappings(maps)
      setRooms(roomList)
      setWorkstations(wsList)
      setWsComPorts(Object.fromEntries(wsList.map(w => [w.id, w.ttlockComPort ?? ''])))
    } catch {
      setError('Не удалось загрузить настройки')
    } finally {
      setLoading(false)
    }
  }, [slug])

  useEffect(() => { load() }, [load])

  const handleSave = async () => {
    setSaving(true)
    setError(null)
    try {
      await api.ttlock.updateConfig(slug, {
        isEnabled,
        clientId:     clientId.trim(),
        clientSecret: clientSecret.trim() || undefined,
        cardSectors:  cardSectors.trim(),
      })
      showSuccess('Настройки сохранены')
      setClientSecret('')
      await load()
    } catch {
      setError('Ошибка сохранения')
    } finally {
      setSaving(false)
    }
  }

  const handleAddMapping = async () => {
    if (!addRoomId || !addLockMac.trim()) return
    setAddLoading(true)
    setError(null)
    try {
      await api.ttlock.mapRoom(slug, {
        roomId:   addRoomId,
        lockMac:  addLockMac.trim(),
        lockName: addLockName.trim() || undefined,
      })
      setAddRoomId('')
      setAddLockMac('')
      setAddLockName('')
      await load()
      showSuccess('Замок привязан к номеру')
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Ошибка привязки замка')
    } finally {
      setAddLoading(false)
    }
  }

  const handleUnmap = async (roomId: string) => {
    try {
      await api.ttlock.unmapRoom(slug, roomId)
      await load()
      showSuccess('Привязка удалена')
    } catch {
      setError('Ошибка удаления привязки')
    }
  }

  const handleLoadPorts = async (wsId: string) => {
    setWsPortsLoading(prev => ({ ...prev, [wsId]: true }))
    try {
      const result = await api.workstations.listPorts(slug, wsId)
      setWsPorts(prev => ({ ...prev, [wsId]: result.ports }))
    } catch {
      // If agent offline or error, leave wsPorts[wsId] undefined — fallback to text input
    } finally {
      setWsPortsLoading(prev => ({ ...prev, [wsId]: false }))
    }
  }

  if (loading) {
    return (
      <div className="flex items-center justify-center h-64">
        <RefreshCw size={24} className="animate-spin text-brand-600" />
      </div>
    )
  }

  const unmappedRooms = rooms.filter(r => !mappings.some(m => m.roomId === r.id))

  return (
    <div className="max-w-3xl mx-auto p-6 space-y-6">

      {/* Header */}
      <div className="flex items-center gap-3">
        <div className="w-10 h-10 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
          <KeyRound size={20} className="text-brand-600 dark:text-brand-400" />
        </div>
        <div>
          <h1 className="text-xl font-bold text-slate-900 dark:text-slate-100">Электронные замки TTLock</h1>
          <p className="text-sm text-slate-500">Автоматическая выдача карт-ключей через программу TTHotel</p>
        </div>
      </div>

      {/* ── Шаг 1: Подключение к TTHotel ── */}
      <Section title="Шаг 1 — Подключение к TTHotel">
        <div className="space-y-5">
          <Hint>
            Откройте программу <strong>TTHotel</strong> на Windows-компьютере →{' '}
            <strong>Настройки → Интеграции</strong>. Скопируйте поля Client ID и Client Secret.
          </Hint>

          {/* Включить/выключить */}
          <div className="flex items-center justify-between">
            <div>
              <p className="font-medium text-slate-800 dark:text-slate-200">Активировать модуль</p>
              <p className="text-xs text-slate-500 mt-0.5">Включает кнопку «Выдать ключ» в карточке бронирования</p>
            </div>
            <button
              onClick={() => setIsEnabled(e => !e)}
              className={cn(
                'relative w-11 h-6 rounded-full transition-colors',
                isEnabled ? 'bg-brand-500' : 'bg-slate-300 dark:bg-slate-600',
              )}
            >
              <span className={cn(
                'absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform',
                isEnabled && 'translate-x-5',
              )} />
            </button>
          </div>

          <div className="grid grid-cols-2 gap-4">
            <div>
              <label className="form-label">Client ID</label>
              <input
                type="text"
                value={clientId}
                onChange={e => setClientId(e.target.value)}
                placeholder="Из TTHotel → Настройки → Интеграции"
                className="input w-full font-mono text-sm"
              />
            </div>
            <div>
              <label className="form-label">Client Secret</label>
              <PasswordInput
                value={clientSecret}
                onChange={setClientSecret}
                placeholder={config?.clientId ? '••••••• (не изменится)' : 'Из TTHotel → Интеграции → Показать'}
              />
            </div>
          </div>

          {/* Секторы карты — визуальный пикер */}
          <div>
            <label className="form-label">Секторы карты</label>
            <SectorPicker value={cardSectors} onChange={setCardSectors} />
          </div>

          <button onClick={handleSave} disabled={saving} className="btn-primary flex items-center gap-2">
            {saving ? <RefreshCw size={15} className="animate-spin" /> : <Save size={15} />}
            Сохранить
          </button>
        </div>
      </Section>

      {/* ── Шаг 2: Рабочие места и энкодеры ── */}
      <Section title="Шаг 2 — Рабочие места и энкодеры">
        <div className="space-y-4">
          <Hint>
            Для каждого рабочего места укажите COM-порт USB-энкодера карт (найти в Диспетчере устройств → Порты).
            Нажмите <strong>↺</strong> рядом с полем, чтобы загрузить список портов с агента.
            Агент должен быть онлайн.
          </Hint>

          {/* Alerts */}
          {error && (
            <div className="flex items-start gap-2 p-4 rounded-xl bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400 text-sm">
              <AlertCircle size={16} className="mt-0.5 shrink-0" />
              <div className="flex-1 space-y-1">
                <span>{error}</span>
                {isDllEntryError(error) && (
                  <div className="mt-2 p-2 rounded bg-red-100 dark:bg-red-900/40 text-xs">
                    <strong>Имена функций в DLL не совпадают.</strong>{' '}
                    Откройте файл{' '}
                    <code className="font-mono">C:\Program Files (x86)\TTHotel\resources\libs\index.js</code>{' '}
                    и сообщите содержимое разработчику.
                  </div>
                )}
              </div>
              <button onClick={() => setError(null)}><X size={14} /></button>
            </div>
          )}
          {success && (
            <div className="flex items-center gap-2 p-4 rounded-xl bg-emerald-50 dark:bg-emerald-900/20 text-emerald-700 dark:text-emerald-400 text-sm">
              <Check size={16} className="shrink-0" />
              <span>{success}</span>
            </div>
          )}

          {workstations.length === 0 && (
            <p className="text-sm text-slate-500">Нет рабочих мест. Добавьте их на странице «Оборудование».</p>
          )}
          <div className="space-y-3">
            {workstations.map(ws => {
              const hasPort = !!wsComPorts[ws.id]?.trim()
              const portList = wsPorts[ws.id]
              const portsLoading = wsPortsLoading[ws.id] ?? false

              return (
                <div
                  key={ws.id}
                  className={cn(
                    'flex items-center gap-3 p-3 rounded-xl border bg-slate-50 dark:bg-slate-800/40',
                    hasPort
                      ? 'border-slate-200 dark:border-slate-700'
                      : 'border-slate-200 dark:border-slate-700 opacity-60',
                  )}
                >
                  {/* Online dot */}
                  <div className={cn('w-2.5 h-2.5 rounded-full shrink-0', ws.isOnline ? 'bg-emerald-500' : 'bg-slate-300 dark:bg-slate-600')} />

                  {/* Name */}
                  <div className="flex-1 min-w-0">
                    <p className="text-sm font-medium text-slate-800 dark:text-slate-200 truncate">{ws.name}</p>
                    {ws.hostname && <p className="text-xs text-slate-400 truncate">{ws.hostname}</p>}
                    {!hasPort && (
                      <p className="text-xs text-amber-500 dark:text-amber-400 mt-0.5">Энкодер не настроен</p>
                    )}
                  </div>

                  {/* COM port — dropdown if ports loaded, text input otherwise */}
                  <div className="flex items-center gap-1 shrink-0">
                    {portList && portList.length > 0 ? (
                      <select
                        className="input w-36 text-sm font-mono py-1.5"
                        value={wsComPorts[ws.id] ?? ''}
                        onChange={e => setWsComPorts(prev => ({ ...prev, [ws.id]: e.target.value }))}
                      >
                        <option value="">— Выберите —</option>
                        {portList.map(p => (
                          <option key={p.port} value={p.port}>
                            {p.port}{p.description ? ` — ${p.description}` : ''}
                          </option>
                        ))}
                      </select>
                    ) : portList && portList.length === 0 ? (
                      <span className="text-xs text-slate-400 w-36 text-center">Порты не найдены</span>
                    ) : (
                      <input
                        type="text"
                        className="input w-28 text-sm font-mono"
                        placeholder="COM3"
                        value={wsComPorts[ws.id] ?? ''}
                        onChange={e => setWsComPorts(prev => ({ ...prev, [ws.id]: e.target.value }))}
                      />
                    )}

                    {/* Load ports button */}
                    <button
                      type="button"
                      onClick={() => handleLoadPorts(ws.id)}
                      disabled={portsLoading || !ws.isOnline}
                      title={!ws.isOnline ? 'Агент офлайн' : 'Загрузить список COM-портов'}
                      className="btn-secondary p-1.5 shrink-0"
                    >
                      {portsLoading
                        ? <RefreshCw size={13} className="animate-spin" />
                        : <RefreshCw size={13} />}
                    </button>
                  </div>

                  {/* Save COM port */}
                  <button
                    type="button"
                    disabled={wsSaving[ws.id]}
                    onClick={async () => {
                      setWsSaving(prev => ({ ...prev, [ws.id]: true }))
                      try {
                        await api.workstations.update(slug, ws.id, { ttlockComPort: wsComPorts[ws.id]?.trim() || null })
                        showSuccess(`COM-порт для «${ws.name}» сохранён`)
                        await load()
                      } catch { setError('Ошибка сохранения') }
                      finally { setWsSaving(prev => ({ ...prev, [ws.id]: false })) }
                    }}
                    className="btn-secondary p-1.5 shrink-0"
                    title="Сохранить COM-порт"
                  >
                    {wsSaving[ws.id]
                      ? <RefreshCw size={13} className="animate-spin" />
                      : <HardDriveDownload size={13} />}
                  </button>

                  {/* Test encoder */}
                  <button
                    type="button"
                    disabled={!ws.isOnline || !hasPort || wsTesting[ws.id]}
                    onClick={async () => {
                      setWsTesting(prev => ({ ...prev, [ws.id]: true }))
                      setError(null)
                      try {
                        await api.ttlock.testEncoder(slug, ws.id)
                        showSuccess(`Энкодер на «${ws.name}» отвечает — всё готово!`)
                      } catch (e) {
                        const msg = e instanceof Error ? e.message : 'Ошибка проверки'
                        setError(msg)
                      } finally { setWsTesting(prev => ({ ...prev, [ws.id]: false })) }
                    }}
                    className="btn-secondary p-1.5 shrink-0"
                    title={!ws.isOnline ? 'Агент офлайн' : !hasPort ? 'Укажите COM-порт' : 'Проверить энкодер'}
                  >
                    {wsTesting[ws.id]
                      ? <RefreshCw size={13} className="animate-spin" />
                      : <Zap size={13} />}
                  </button>

                  {/* Diagnose DLL */}
                  <button
                    type="button"
                    disabled={!ws.isOnline}
                    onClick={async () => {
                      setError(null)
                      try {
                        await api.ttlock.testEncoder(slug, ws.id)
                        showSuccess(`Диагностика «${ws.name}»: DLL загружена успешно`)
                      } catch (e) {
                        const msg = e instanceof Error ? e.message : 'Ошибка диагностики DLL'
                        setError(msg)
                      }
                    }}
                    className="btn-secondary p-1.5 shrink-0"
                    title={!ws.isOnline ? 'Агент офлайн' : 'Диагностика DLL'}
                  >
                    <Terminal size={13} />
                  </button>
                </div>
              )
            })}
          </div>
        </div>
      </Section>

      {/* ── Шаг 3: Привязка номеров к замкам ── */}
      <Section title="Шаг 3 — Привязка номеров к замкам">
        <div className="space-y-5">
          <Hint>
            MAC-адрес замка: войдите на <strong>lock.ttlock.com</strong> →{' '}
            нажмите <strong>Manage</strong> у нужного замка → иконка шестерёнки →{' '}
            <strong>Basic</strong> → скопируйте поле <strong>MAC</strong>.
            Введите без двоеточий: <code className="bg-blue-100 dark:bg-blue-900/40 px-1 rounded font-mono">42A6BBF5ECE5</code>
          </Hint>

          {/* Форма добавления */}
          {unmappedRooms.length > 0 && (
            <div className="p-4 bg-slate-50 dark:bg-slate-800/50 rounded-xl space-y-3">
              <p className="text-sm font-medium text-slate-700 dark:text-slate-300">Добавить привязку</p>
              <div className="grid grid-cols-3 gap-3">
                <div>
                  <label className="form-label">Номер</label>
                  <select value={addRoomId} onChange={e => setAddRoomId(e.target.value)} className="input w-full">
                    <option value="">— Выберите —</option>
                    {unmappedRooms.map(r => (
                      <option key={r.id} value={r.id}>
                        №{r.number}{r.name ? ` ${r.name}` : ''}
                      </option>
                    ))}
                  </select>
                </div>
                <div>
                  <label className="form-label">MAC замка</label>
                  <input
                    type="text"
                    value={addLockMac}
                    onChange={e => setAddLockMac(e.target.value.replace(/[^0-9A-Fa-f:]/g, '').toUpperCase())}
                    placeholder="42A6BBF5ECE5"
                    maxLength={17}
                    className="input w-full font-mono text-sm"
                  />
                </div>
                <div>
                  <label className="form-label">Название (необяз.)</label>
                  <input
                    type="text"
                    value={addLockName}
                    onChange={e => setAddLockName(e.target.value)}
                    placeholder="Замок номера 101"
                    className="input w-full"
                  />
                </div>
              </div>
              <button
                onClick={handleAddMapping}
                disabled={!addRoomId || !addLockMac.trim() || addLoading}
                className="btn-primary flex items-center gap-2"
              >
                {addLoading ? <RefreshCw size={15} className="animate-spin" /> : <Plus size={15} />}
                Привязать
              </button>
            </div>
          )}

          {/* Список привязок */}
          {mappings.length > 0 ? (
            <div className="space-y-2">
              {mappings.map(m => (
                <div
                  key={m.roomId}
                  className="flex items-center justify-between p-3 rounded-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900"
                >
                  <div className="flex items-center gap-3">
                    <div className="w-8 h-8 rounded-lg bg-brand-50 dark:bg-brand-900/20 flex items-center justify-center shrink-0">
                      <Lock size={14} className="text-brand-600 dark:text-brand-400" />
                    </div>
                    <div>
                      <p className="text-sm font-medium text-slate-800 dark:text-slate-200">
                        Номер {m.roomNumber}{m.roomName ? ` — ${m.roomName}` : ''}
                      </p>
                      <p className="text-xs text-slate-500 font-mono">
                        {m.lockMac}
                        {m.lockName && <span className="text-slate-400 font-sans ml-2">{m.lockName}</span>}
                      </p>
                    </div>
                  </div>
                  <button
                    onClick={() => handleUnmap(m.roomId)}
                    className="btn-ghost p-2 text-red-500 hover:text-red-700"
                    title="Удалить привязку"
                  >
                    <Trash2 size={15} />
                  </button>
                </div>
              ))}
            </div>
          ) : (
            <div className="text-center py-8 text-slate-400 dark:text-slate-600">
              <Unlock size={32} className="mx-auto mb-2 opacity-40" />
              <p className="text-sm">Нет привязанных замков</p>
              <p className="text-xs mt-1">Добавьте MAC-адреса замков для каждого номера</p>
            </div>
          )}

          {rooms.length > 0 && unmappedRooms.length === 0 && mappings.length > 0 && (
            <p className="text-xs text-emerald-600 dark:text-emerald-400 flex items-center gap-1">
              <Check size={12} /> Все номера привязаны к замкам
            </p>
          )}
        </div>
      </Section>

    </div>
  )
}

export default TTLockPage
