import { useState, useEffect, useCallback } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Play, Plus, X, Database as DatabaseIcon, Clock, CheckCircle, XCircle, Loader2 } from 'lucide-react';
import { databasesApi, sqlInterfaceApi, SqlQueryResult } from '@/services/api';
import { Database } from '@/types';
import SqlEditor from '@/components/SqlEditor';

interface SqlTab {
  id: string;
  name: string;
  query: string;
  databaseId: string;
  result: SqlQueryResult | null;
  isExecuting: boolean;
}

interface SqlInterfaceState {
  tabs: SqlTab[];
  activeTabId: string;
}

const STORAGE_KEY = 'sql_interface_state';

const generateTabId = () => `tab_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

const createNewTab = (databaseId: string = '', name?: string): SqlTab => ({
  id: generateTabId(),
  name: name || 'Новый запрос',
  query: '',
  databaseId,
  result: null,
  isExecuting: false,
});

const loadState = (): SqlInterfaceState | null => {
  try {
    const saved = localStorage.getItem(STORAGE_KEY);
    if (saved) {
      return JSON.parse(saved);
    }
  } catch (e) {
    console.error('Failed to load SQL interface state:', e);
  }
  return null;
};

const saveState = (state: SqlInterfaceState) => {
  try {
    // Don't save isExecuting state and large results
    const stateToSave = {
      ...state,
      tabs: state.tabs.map(tab => ({
        ...tab,
        isExecuting: false,
        result: tab.result ? {
          ...tab.result,
          data: tab.result.data?.slice(0, 100), // Limit saved results
        } : null,
      })),
    };
    localStorage.setItem(STORAGE_KEY, JSON.stringify(stateToSave));
  } catch (e) {
    console.error('Failed to save SQL interface state:', e);
  }
};

export default function SqlInterface() {
  const { data: databases = [], isLoading: isLoadingDatabases } = useQuery({
    queryKey: ['databases'],
    queryFn: async () => {
      const { data } = await databasesApi.getAll();
      // Filter only SQL databases (not AQL)
      return data.filter((db: Database) => db.type !== 'aql');
    },
  });

  const [state, setState] = useState<SqlInterfaceState>(() => {
    const saved = loadState();
    if (saved && saved.tabs.length > 0) {
      return saved;
    }
    const initialTab = createNewTab();
    return {
      tabs: [initialTab],
      activeTabId: initialTab.id,
    };
  });

  // Save state to localStorage on changes
  useEffect(() => {
    saveState(state);
  }, [state]);

  // Set default database for new tabs when databases load
  useEffect(() => {
    if (databases.length > 0) {
      setState(prev => ({
        ...prev,
        tabs: prev.tabs.map(tab =>
          tab.databaseId === '' ? { ...tab, databaseId: databases[0].id } : tab
        ),
      }));
    }
  }, [databases]);

  const activeTab = state.tabs.find(t => t.id === state.activeTabId) || state.tabs[0];

  const updateTab = useCallback((tabId: string, updates: Partial<SqlTab>) => {
    setState(prev => ({
      ...prev,
      tabs: prev.tabs.map(tab =>
        tab.id === tabId ? { ...tab, ...updates } : tab
      ),
    }));
  }, []);

  const addTab = useCallback(() => {
    const defaultDbId = databases.length > 0 ? databases[0].id : '';
    const newTab = createNewTab(defaultDbId, `Запрос ${state.tabs.length + 1}`);
    setState(prev => ({
      tabs: [...prev.tabs, newTab],
      activeTabId: newTab.id,
    }));
  }, [databases, state.tabs.length]);

  const closeTab = useCallback((tabId: string, e: React.MouseEvent) => {
    e.stopPropagation();
    setState(prev => {
      if (prev.tabs.length === 1) {
        // Don't close the last tab, just reset it
        const defaultDbId = databases.length > 0 ? databases[0].id : '';
        const newTab = createNewTab(defaultDbId);
        return {
          tabs: [newTab],
          activeTabId: newTab.id,
        };
      }

      const newTabs = prev.tabs.filter(t => t.id !== tabId);
      const newActiveId = prev.activeTabId === tabId
        ? newTabs[Math.max(0, prev.tabs.findIndex(t => t.id === tabId) - 1)].id
        : prev.activeTabId;

      return {
        tabs: newTabs,
        activeTabId: newActiveId,
      };
    });
  }, [databases]);

  const setActiveTab = useCallback((tabId: string) => {
    setState(prev => ({ ...prev, activeTabId: tabId }));
  }, []);

  const executeQuery = useCallback(async () => {
    if (!activeTab || !activeTab.databaseId || !activeTab.query.trim()) {
      return;
    }

    updateTab(activeTab.id, { isExecuting: true, result: null });

    try {
      const { data } = await sqlInterfaceApi.execute(activeTab.databaseId, activeTab.query);
      updateTab(activeTab.id, { isExecuting: false, result: data });
    } catch (error: any) {
      updateTab(activeTab.id, {
        isExecuting: false,
        result: {
          success: false,
          error: error.response?.data?.error || error.message || 'Query execution failed',
          detail: error.response?.data?.detail,
          hint: error.response?.data?.hint,
        },
      });
    }
  }, [activeTab, updateTab]);

  // Keyboard shortcut for execute (Ctrl+Enter or Cmd+Enter)
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
        e.preventDefault();
        executeQuery();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [executeQuery]);

  const selectedDatabase = databases.find((db: Database) => db.id === activeTab?.databaseId);

  if (isLoadingDatabases) {
    return (
      <div className="flex items-center justify-center h-64">
        <Loader2 className="animate-spin text-primary-600" size={32} />
      </div>
    );
  }

  return (
    <div className="flex flex-col -m-8 bg-white" style={{ height: 'calc(100vh - 64px)' }}>
      {/* Tabs bar */}
      <div className="flex items-center bg-gray-100 border-b border-gray-200 px-2">
        <div className="flex-1 flex items-center overflow-x-auto">
          {state.tabs.map(tab => (
            <button
              key={tab.id}
              onClick={() => setActiveTab(tab.id)}
              className={`
                flex items-center gap-2 px-4 py-2 text-sm border-r border-gray-200
                ${tab.id === state.activeTabId
                  ? 'bg-white text-gray-900 font-medium'
                  : 'text-gray-600 hover:bg-gray-50'
                }
              `}
            >
              <span className="max-w-32 truncate">{tab.name}</span>
              {tab.isExecuting && <Loader2 className="animate-spin" size={14} />}
              <button
                onClick={(e) => closeTab(tab.id, e)}
                className="ml-1 p-0.5 rounded hover:bg-gray-200 text-gray-400 hover:text-gray-600"
              >
                <X size={14} />
              </button>
            </button>
          ))}
        </div>
        <button
          onClick={addTab}
          className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-200 rounded"
          title="Новая вкладка"
        >
          <Plus size={18} />
        </button>
      </div>

      {/* Toolbar */}
      <div className="flex items-center gap-4 p-3 border-b border-gray-200 bg-gray-50">
        {/* Database selector */}
        <div className="flex items-center gap-2">
          <DatabaseIcon size={18} className="text-gray-500" />
          <select
            value={activeTab?.databaseId || ''}
            onChange={(e) => updateTab(activeTab.id, { databaseId: e.target.value })}
            className="border border-gray-300 rounded-md px-3 py-1.5 text-sm bg-white focus:outline-none focus:ring-2 focus:ring-primary-500 min-w-48"
          >
            <option value="">Выберите базу данных</option>
            {databases.map((db: Database) => (
              <option key={db.id} value={db.id}>
                {db.name} ({db.type})
              </option>
            ))}
          </select>
        </div>

        {/* Execute button */}
        <button
          onClick={executeQuery}
          disabled={!activeTab?.databaseId || !activeTab?.query.trim() || activeTab?.isExecuting}
          className="flex items-center gap-2 px-4 py-1.5 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed text-sm font-medium"
        >
          {activeTab?.isExecuting ? (
            <Loader2 className="animate-spin" size={16} />
          ) : (
            <Play size={16} />
          )}
          Выполнить
          <span className="text-xs opacity-75 ml-1">(Ctrl+Enter)</span>
        </button>

        {/* Tab name editor */}
        <input
          type="text"
          value={activeTab?.name || ''}
          onChange={(e) => updateTab(activeTab.id, { name: e.target.value })}
          className="border border-gray-300 rounded-md px-3 py-1.5 text-sm bg-white focus:outline-none focus:ring-2 focus:ring-primary-500 w-48"
          placeholder="Название вкладки"
        />
      </div>

      {/* Main content area */}
      <div className="flex-1 flex flex-col min-h-0">
        {/* SQL Editor */}
        <div className="h-1/2 min-h-48 border-b border-gray-200">
          <SqlEditor
            value={activeTab?.query || ''}
            onChange={(value) => updateTab(activeTab.id, { query: value })}
            databaseId={activeTab?.databaseId}
            height="100%"
          />
        </div>

        {/* Results panel */}
        <div className="flex-1 min-h-0 flex flex-col bg-white">
          {/* Result header */}
          {activeTab?.result && (
            <div className="flex items-center gap-4 px-4 py-2 bg-gray-50 border-b border-gray-200 text-sm">
              {activeTab.result.success ? (
                <>
                  <div className="flex items-center gap-1 text-green-600">
                    <CheckCircle size={16} />
                    <span>Успешно</span>
                  </div>
                  <div className="flex items-center gap-1 text-gray-600">
                    <span>{activeTab.result.rowCount ?? 0} строк</span>
                  </div>
                  {activeTab.result.executionTime !== undefined && (
                    <div className="flex items-center gap-1 text-gray-500">
                      <Clock size={14} />
                      <span>{activeTab.result.executionTime} мс</span>
                    </div>
                  )}
                  {activeTab.result.command && (
                    <span className="text-gray-400">{activeTab.result.command}</span>
                  )}
                </>
              ) : (
                <div className="flex items-center gap-1 text-red-600">
                  <XCircle size={16} />
                  <span>Ошибка</span>
                </div>
              )}
            </div>
          )}

          {/* Result content */}
          <div className="flex-1 overflow-auto">
            {!activeTab?.result && !activeTab?.isExecuting && (
              <div className="flex items-center justify-center h-full text-gray-400">
                Выполните запрос, чтобы увидеть результаты
              </div>
            )}

            {activeTab?.isExecuting && (
              <div className="flex items-center justify-center h-full">
                <Loader2 className="animate-spin text-primary-600" size={32} />
              </div>
            )}

            {activeTab?.result && !activeTab.result.success && (
              <div className="p-4">
                <div className="bg-red-50 border border-red-200 rounded-lg p-4">
                  <p className="text-red-700 font-medium">{activeTab.result.error}</p>
                  {activeTab.result.detail && (
                    <p className="text-red-600 mt-2 text-sm">{activeTab.result.detail}</p>
                  )}
                  {activeTab.result.hint && (
                    <p className="text-red-500 mt-2 text-sm italic">Подсказка: {activeTab.result.hint}</p>
                  )}
                </div>
              </div>
            )}

            {activeTab?.result?.success && activeTab.result.data && (
              <ResultTable
                data={activeTab.result.data}
                fields={activeTab.result.fields || []}
              />
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

interface ResultTableProps {
  data: any[];
  fields: { name: string; dataTypeID: number }[];
}

function ResultTable({ data, fields }: ResultTableProps) {
  if (data.length === 0) {
    return (
      <div className="flex items-center justify-center h-full text-gray-400">
        Запрос выполнен успешно, но не вернул данных
      </div>
    );
  }

  const columns = fields.length > 0
    ? fields.map(f => f.name)
    : Object.keys(data[0] || {});

  return (
    <div className="overflow-auto h-full">
      <table className="w-full text-sm">
        <thead className="bg-gray-100 sticky top-0">
          <tr>
            <th className="px-3 py-2 text-left text-xs font-medium text-gray-500 border-r border-b border-gray-200 w-12">
              #
            </th>
            {columns.map(col => (
              <th
                key={col}
                className="px-3 py-2 text-left text-xs font-medium text-gray-600 border-r border-b border-gray-200 whitespace-nowrap"
              >
                {col}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {data.map((row, rowIndex) => (
            <tr key={rowIndex} className="hover:bg-gray-50 border-b border-gray-100">
              <td className="px-3 py-1.5 text-gray-400 border-r border-gray-100 text-xs">
                {rowIndex + 1}
              </td>
              {columns.map(col => (
                <td
                  key={col}
                  className="px-3 py-1.5 border-r border-gray-100 max-w-md truncate"
                  title={formatCellValue(row[col])}
                >
                  {formatCellValue(row[col])}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function formatCellValue(value: any): string {
  if (value === null) return 'NULL';
  if (value === undefined) return '';
  if (typeof value === 'object') return JSON.stringify(value);
  return String(value);
}
