import { useState, useEffect } from 'react'
import { configStorage } from '@/lib/configStorage'
import type { Nip95Config } from '@/lib/configStorageTypes'
import { t } from '@/lib/i18n'
import { userConfirm } from '@/lib/userConfirm'
import { DragHandle } from './DragHandle'

interface Nip95ConfigManagerProps {
  onConfigChange?: () => void
}

export function Nip95ConfigManager({ onConfigChange }: Nip95ConfigManagerProps): React.ReactElement {
  const [apis, setApis] = useState<Nip95Config[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [editingId, setEditingId] = useState<string | null>(null)
  const [newUrl, setNewUrl] = useState('')
  const [showAddForm, setShowAddForm] = useState(false)
  const [draggedId, setDraggedId] = useState<string | null>(null)
  const [dragOverId, setDragOverId] = useState<string | null>(null)

  useEffect(() => {
    void loadApis()
  }, [])

  async function loadApis(): Promise<void> {
    try {
      setLoading(true)
      setError(null)
      const config = await configStorage.getConfig()
      setApis(config.nip95Apis.sort((a, b) => a.priority - b.priority))
    } catch (e) {
      const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.loadFailed')
      setError(errorMessage)
      console.error('Error loading NIP-95 APIs:', e)
    } finally {
      setLoading(false)
    }
  }

  async function handleToggleEnabled(id: string, enabled: boolean): Promise<void> {
    try {
      await configStorage.updateNip95Api(id, { enabled })
      await loadApis()
      onConfigChange?.()
    } catch (e) {
      const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.updateFailed')
      setError(errorMessage)
      console.error('Error updating NIP-95 API:', e)
    }
  }

  async function handleUpdatePriorities(newOrder: Nip95Config[]): Promise<void> {
    try {
      // Update priorities based on new order (priority = index + 1, lower number = higher priority)
      const updatePromises = newOrder.map((api, index) => {
        const newPriority = index + 1
        if (api.priority !== newPriority) {
          return configStorage.updateNip95Api(api.id, { priority: newPriority })
        }
        return Promise.resolve()
      })

      await Promise.all(updatePromises)
      await loadApis()
      onConfigChange?.()
    } catch (e) {
      const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.priorityFailed')
      setError(errorMessage)
      console.error('Error updating priorities:', e)
    }
  }

  function handleDragStart(e: React.DragEvent<HTMLDivElement>, id: string): void {
    setDraggedId(id)
    const { dataTransfer } = e
    dataTransfer.effectAllowed = 'move'
    dataTransfer.setData('text/plain', id)
  }

  function handleDragOver(e: React.DragEvent<HTMLDivElement>, id: string): void {
    e.preventDefault()
    const { dataTransfer } = e
    dataTransfer.dropEffect = 'move'
    setDragOverId(id)
  }

  function handleDragLeave(): void {
    setDragOverId(null)
  }

  function handleDrop(e: React.DragEvent<HTMLDivElement>, targetId: string): void {
    e.preventDefault()
    setDragOverId(null)

    if (!draggedId || draggedId === targetId) {
      setDraggedId(null)
      return
    }

    const draggedIndex = apis.findIndex((api) => api.id === draggedId)
    const targetIndex = apis.findIndex((api) => api.id === targetId)

    if (draggedIndex === -1 || targetIndex === -1) {
      setDraggedId(null)
      return
    }

    // Reorder the array
    const newApis = [...apis]
    const removed = newApis[draggedIndex]
    if (!removed) {
      setDraggedId(null)
      return
    }
    newApis.splice(draggedIndex, 1)
    newApis.splice(targetIndex, 0, removed)

    setApis(newApis)
    setDraggedId(null)

    // Update priorities based on new order
    void handleUpdatePriorities(newApis)
  }

  async function handleUpdateUrl(id: string, url: string): Promise<void> {
    try {
      await configStorage.updateNip95Api(id, { url })
      await loadApis()
      setEditingId(null)
      onConfigChange?.()
    } catch (e) {
      const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.urlFailed')
      setError(errorMessage)
      console.error('Error updating URL:', e)
    }
  }

  async function handleAddApi(): Promise<void> {
    if (!newUrl.trim()) {
      setError(t('settings.nip95.error.urlRequired'))
      return
    }

    try {
      // Validate URL format - throws if invalid
      void new URL(newUrl)
      await configStorage.addNip95Api(newUrl.trim(), false)
      setNewUrl('')
      setShowAddForm(false)
      await loadApis()
      onConfigChange?.()
    } catch (e) {
      if (e instanceof TypeError && e.message.includes('Invalid URL')) {
        setError(t('settings.nip95.error.invalidUrl'))
      } else {
        const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.addFailed')
        setError(errorMessage)
      }
      console.error('Error adding NIP-95 API:', e)
    }
  }

  async function handleRemoveApi(id: string): Promise<void> {
    const confirmed = await userConfirm(t('settings.nip95.remove.confirm'))
    if (!confirmed) {
      return
    }

    try {
      await configStorage.removeNip95Api(id)
      await loadApis()
      onConfigChange?.()
    } catch (e) {
      const errorMessage = e instanceof Error ? e.message : t('settings.nip95.error.removeFailed')
      setError(errorMessage)
      console.error('Error removing NIP-95 API:', e)
    }
  }

  if (loading) {
    return (
      <div className="text-center py-8 text-neon-cyan">
        <div>{t('settings.nip95.loading')}</div>
      </div>
    )
  }

  return (
    <div className="space-y-6">
      {error && (
        <div className="bg-red-900/30 border border-red-500/50 rounded p-4 text-red-300">
          {error}
          <button
            onClick={() => setError(null)}
            className="ml-4 text-red-400 hover:text-red-200"
          >
            ×
          </button>
        </div>
      )}

      <div className="flex justify-between items-center">
        <h2 className="text-2xl font-bold text-neon-cyan">{t('settings.nip95.title')}</h2>
        <button
          onClick={() => setShowAddForm(!showAddForm)}
          className="px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border border-neon-cyan/50 rounded transition-colors"
        >
          {showAddForm ? t('settings.nip95.add.cancel') : t('settings.nip95.addButton')}
        </button>
      </div>

      {showAddForm && (
        <div className="bg-cyber-dark border border-neon-cyan/30 rounded p-4 space-y-4">
          <div>
            <label className="block text-sm font-medium text-cyber-accent mb-2">
              {t('settings.nip95.add.url')}
            </label>
            <input
              type="url"
              value={newUrl}
              onChange={(e) => setNewUrl(e.target.value)}
              placeholder={t('settings.nip95.add.placeholder')}
              className="w-full px-4 py-2 bg-cyber-darker border border-cyber-accent/30 rounded text-cyber-light focus:border-neon-cyan focus:outline-none"
            />
          </div>
          <div className="flex gap-2">
            <button
              onClick={() => void handleAddApi()}
              className="px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan border border-neon-cyan/50 rounded transition-colors"
            >
              {t('settings.nip95.add.add')}
            </button>
            <button
              onClick={() => {
                setShowAddForm(false)
                setNewUrl('')
                setError(null)
              }}
              className="px-4 py-2 bg-cyber-accent/20 hover:bg-cyber-accent/30 text-cyber-accent border border-cyber-accent/50 rounded transition-colors"
            >
              {t('settings.nip95.add.cancel')}
            </button>
          </div>
        </div>
      )}

      <div className="space-y-4">
        {apis.length === 0 ? (
          <div className="text-center py-8 text-cyber-accent">
            {t('settings.nip95.empty')}
          </div>
        ) : (
          apis.map((api, index) => (
            <div
              key={api.id}
              onDragOver={(e) => {
                handleDragOver(e, api.id)
              }}
              onDragLeave={handleDragLeave}
              onDrop={(e) => {
                handleDrop(e, api.id)
              }}
              className={`bg-cyber-dark border rounded p-4 space-y-3 transition-all ${getApiCardClassName(api.id, draggedId, dragOverId)}`}
            >
              <div className="flex items-start justify-between gap-4">
                <div className="flex items-center gap-3 flex-1">
                  <div
                    className="drag-handle cursor-grab active:cursor-grabbing"
                    draggable
                    onDragStart={(e) => {
                      handleDragStart(e, api.id)
                      e.stopPropagation()
                    }}
                    onMouseDown={(e) => {
                      e.stopPropagation()
                    }}
                  >
                    <DragHandle />
                  </div>
                  <div className="flex-1">
                  {editingId === api.id ? (
                    <div className="space-y-2">
                      <input
                        type="url"
                        defaultValue={api.url}
                        onBlur={(e) => {
                          if (e.target.value !== api.url) {
                            void handleUpdateUrl(api.id, e.target.value)
                          } else {
                            setEditingId(null)
                          }
                        }}
                        onKeyDown={(e) => {
                          if (e.key === 'Enter') {
                            e.currentTarget.blur()
                          } else if (e.key === 'Escape') {
                            setEditingId(null)
                          }
                        }}
                        className="w-full px-3 py-2 bg-cyber-darker border border-neon-cyan/50 rounded text-cyber-light focus:border-neon-cyan focus:outline-none"
                        autoFocus
                      />
                    </div>
                  ) : (
                    <div
                      className="text-neon-cyan cursor-pointer hover:text-neon-green transition-colors"
                      onClick={() => setEditingId(api.id)}
                      title={t('settings.nip95.list.editUrl')}
                    >
                      {api.url}
                    </div>
                  )}
                  </div>
                </div>
                <div className="flex items-center gap-2">
                  <label className="flex items-center gap-2 cursor-pointer">
                    <input
                      type="checkbox"
                      checked={api.enabled}
                      onChange={(e) => void handleToggleEnabled(api.id, e.target.checked)}
                      className="w-4 h-4 text-neon-cyan bg-cyber-darker border-cyber-accent rounded focus:ring-neon-cyan"
                    />
                    <span className="text-sm text-cyber-accent">
                      {api.enabled ? t('settings.nip95.list.enabled') : t('settings.nip95.list.disabled')}
                    </span>
                  </label>
                  <button
                    onClick={() => void handleRemoveApi(api.id)}
                    className="px-3 py-1 text-sm bg-red-900/30 hover:bg-red-900/50 text-red-300 border border-red-500/50 rounded transition-colors"
                    title={t('settings.nip95.list.remove')}
                  >
                    {t('settings.nip95.list.remove')}
                  </button>
                </div>
              </div>
              <div className="flex items-center gap-2 text-xs text-cyber-accent/70">
                <span>
                  {t('settings.nip95.list.priorityLabel', { priority: index + 1, id: api.id })}
                </span>
              </div>
            </div>
          ))
        )}
      </div>

      <div className="text-sm text-cyber-accent space-y-2">
        <p>
          <strong>{t('settings.nip95.note.title')}</strong> {t('settings.nip95.note.priority')}
        </p>
        <p>
          {t('settings.nip95.note.fallback')}
        </p>
      </div>
    </div>
  )
}

function getApiCardClassName(apiId: string, draggedId: string | null, dragOverId: string | null): string {
  if (draggedId === apiId) {
    return 'opacity-50 border-neon-cyan'
  }
  if (dragOverId === apiId) {
    return 'border-neon-green shadow-lg'
  }
  return 'border-neon-cyan/30'
}
