import { useState, useEffect } from 'react'
import {
  FaRegFolder,
  FaRegFolderOpen,
  FaColumns,
  FaSyncAlt,
  FaTable,
  FaPlus,
  FaEye,
  FaCog,
  FaCode,
  FaDatabase,
  FaTrash,
} from 'react-icons/fa'
import type { DatabaseTableDto, SqlNativeObjectDto } from '@/proxy/sql-query-manager/models'
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
import { useLocalization } from '@/utils/hooks/useLocalization'

type FolderKey = 'tables' | 'views' | 'procedures' | 'functions'

interface TreeNode {
  id: string
  label: string
  type: 'root' | 'folder' | 'object'
  folder?: FolderKey
  data?: DatabaseTableDto | SqlNativeObjectDto
  children?: TreeNode[]
}

interface SqlObjectExplorerProps {
  dataSource: string | null
  onTemplateSelect?: (template: string, templateType: string) => void
  onViewDefinition?: (schemaName: string, objectName: string) => void
  onGenerateTableScript?: (schemaName: string, tableName: string) => void
  onDesignTable?: (schemaName: string, tableName: string) => void
  onNewTable?: () => void
  onSelectedObjectsChange?: (objects: SqlExplorerSelectedObject[]) => void
  refreshTrigger?: number
}

export interface SqlExplorerSelectedObject {
  id: string
  objectType: 'table' | 'view' | 'procedure' | 'function'
  schemaName: string
  objectName: string
  fullName: string
}

const FOLDER_META: Record<FolderKey, { label: string; color: string }> = {
  tables:     { label: 'Tables',             color: 'text-teal-500' },
  views:      { label: 'Views',              color: 'text-purple-500' },
  procedures: { label: 'Stored Procedures',  color: 'text-green-600' },
  functions:  { label: 'Functions',          color: 'text-orange-500' },
}

const SqlObjectExplorer = ({
  dataSource,
  onTemplateSelect,
  onViewDefinition,
  onGenerateTableScript,
  onDesignTable,
  onNewTable,
  onSelectedObjectsChange,
  refreshTrigger,
}: SqlObjectExplorerProps) => {
  const { translate } = useLocalization()
  const [treeData, setTreeData] = useState<TreeNode[]>([])
  const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set(['root']))
  const [loading, setLoading] = useState(false)
  const [filterText, setFilterText] = useState('')
  const [selectedObjectIds, setSelectedObjectIds] = useState<Set<string>>(new Set())
  const [dropConfirm, setDropConfirm] = useState<{ node: TreeNode } | null>(null)
  const [dropping, setDropping] = useState(false)
  const [contextMenu, setContextMenu] = useState<{
    show: boolean; x: number; y: number; node: TreeNode | null
  }>({ show: false, x: 0, y: 0, node: null })

  useEffect(() => {
    if (dataSource) {
      loadObjects()
    } else {
      setTreeData([])
      setSelectedObjectIds(new Set())
      onSelectedObjectsChange?.([])
    }
  }, [dataSource, refreshTrigger])

  useEffect(() => {
    const selected = getSelectedObjects(treeData, selectedObjectIds)
    onSelectedObjectsChange?.(selected)
  }, [treeData, selectedObjectIds, onSelectedObjectsChange])

  const loadObjects = async () => {
    if (!dataSource) return
    setLoading(true)
    try {
      const { data } = await sqlObjectManagerService.getAllObjects(dataSource)

      const makeObjectNode = (folder: FolderKey, obj: SqlNativeObjectDto): TreeNode => ({
        id: `${folder}-${obj.schemaName}-${obj.objectName}`,
        label: obj.fullName ?? `[${obj.schemaName}].[${obj.objectName}]`,
        type: 'object',
        folder,
        data: obj,
      })

      const tree: TreeNode[] = [{
        id: 'root',
        label: dataSource,
        type: 'root',
        children: [
          {
            id: 'tables',
            label: `Tables (${data.tables.length})`,
            type: 'folder',
            folder: 'tables',
            children: data.tables.map((t) => ({
              id: `tables-${t.schemaName}-${t.tableName}`,
              label: t.fullName ?? `[${t.schemaName}].[${t.tableName}]`,
              type: 'object' as const,
              folder: 'tables' as FolderKey,
              data: t,
            })),
          },
          {
            id: 'views',
            label: `Views (${data.views.length})`,
            type: 'folder',
            folder: 'views',
            children: data.views.map((v) => makeObjectNode('views', v)),
          },
          {
            id: 'procedures',
            label: `Stored Procedures (${data.storedProcedures.length})`,
            type: 'folder',
            folder: 'procedures',
            children: data.storedProcedures.map((p) => makeObjectNode('procedures', p)),
          },
          {
            id: 'functions',
            label: `Functions (${data.functions.length})`,
            type: 'folder',
            folder: 'functions',
            children: data.functions.map((f) => makeObjectNode('functions', f)),
          },
        ],
      }]

      setTreeData(tree)
    } catch (error: any) {
      console.error('Failed to load objects', error)
    } finally {
      setLoading(false)
    }
  }

  const toggleNode = (nodeId: string) => {
    setExpandedNodes((prev) => {
      const next = new Set(prev)
      next.has(nodeId) ? next.delete(nodeId) : next.add(nodeId)
      return next
    })
  }

  const filterTree = (nodes: TreeNode[], search: string): TreeNode[] => {
    if (!search.trim()) return nodes
    const q = search.toLowerCase()
    return nodes
      .map((node) => {
        const match = node.label.toLowerCase().includes(q)
        const kids = node.children ? filterTree(node.children, search) : []
        if (match || kids.length > 0)
          return { ...node, children: kids.length > 0 ? kids : node.children } as TreeNode
        return null
      })
      .filter(Boolean) as TreeNode[]
  }

  const handleNodeClick = (node: TreeNode) => {
    if (node.type !== 'object') { toggleNode(node.id); return }

    if (node.folder === 'tables') {
      // Generate SELECT template for tables
      const t = node.data as DatabaseTableDto
      onTemplateSelect?.(`SELECT TOP 10 *\nFROM ${t.fullName ?? `[${t.schemaName}].[${t.tableName}]`};`, 'table-select')
    } else {
      // Load native object definition into editor
      const obj = node.data as SqlNativeObjectDto
      onViewDefinition?.(obj.schemaName, obj.objectName)
    }
  }

  const mapNodeToSelectedObject = (node: TreeNode): SqlExplorerSelectedObject | null => {
    if (node.type !== 'object' || !node.folder || !node.data) return null

    if (node.folder === 'tables') {
      const t = node.data as DatabaseTableDto
      return {
        id: node.id,
        objectType: 'table',
        schemaName: t.schemaName,
        objectName: t.tableName,
        fullName: t.fullName ?? `[${t.schemaName}].[${t.tableName}]`,
      }
    }

    const obj = node.data as SqlNativeObjectDto
    const objectType =
      node.folder === 'views'
        ? 'view'
        : node.folder === 'procedures'
          ? 'procedure'
          : 'function'

    return {
      id: node.id,
      objectType,
      schemaName: obj.schemaName,
      objectName: obj.objectName,
      fullName: obj.fullName ?? `[${obj.schemaName}].[${obj.objectName}]`,
    }
  }

  const getSelectedObjects = (nodes: TreeNode[], ids: Set<string>): SqlExplorerSelectedObject[] => {
    const selected: SqlExplorerSelectedObject[] = []

    const walk = (list: TreeNode[]) => {
      for (const node of list) {
        if (node.type === 'object' && ids.has(node.id)) {
          const mapped = mapNodeToSelectedObject(node)
          if (mapped) selected.push(mapped)
        }
        if (node.children?.length) walk(node.children)
      }
    }

    walk(nodes)
    return selected
  }

  const toggleObjectSelection = (nodeId: string, checked: boolean) => {
    setSelectedObjectIds((prev) => {
      const next = new Set(prev)
      if (checked) next.add(nodeId)
      else next.delete(nodeId)
      return next
    })
  }

  const buildDropSql = (node: TreeNode): string => {
    if (node.folder === 'tables') {
      const t = node.data as DatabaseTableDto
      return `DROP TABLE ${t.fullName ?? `[${t.schemaName}].[${t.tableName}]`};`
    }
    const obj = node.data as SqlNativeObjectDto
    const keyword =
      node.folder === 'views'      ? 'VIEW' :
      node.folder === 'procedures' ? 'PROCEDURE' :
                                     'FUNCTION'
    return `DROP ${keyword} ${obj.fullName ?? `[${obj.schemaName}].[${obj.objectName}]`};`
  }

  const handleDrop = async () => {
    if (!dropConfirm || !dataSource) return
    setDropping(true)
    try {
      await sqlObjectManagerService.executeQuery({
        queryText: buildDropSql(dropConfirm.node),
        dataSourceCode: dataSource,
      })
      setDropConfirm(null)
      loadObjects()
    } catch (err: any) {
      console.error('Drop failed', err)
    } finally {
      setDropping(false)
    }
  }

  const closeCtx = () => setContextMenu({ show: false, x: 0, y: 0, node: null })

  const getIcon = (node: TreeNode) => {
    if (node.type === 'root') return <FaDatabase className="text-blue-500" />
    if (node.type === 'folder') {
      const open = expandedNodes.has(node.id)
      const cls = FOLDER_META[node.folder!]?.color ?? 'text-blue-500'
      return open
        ? <FaRegFolderOpen className={cls} />
        : <FaRegFolder className={cls} />
    }
    if (node.folder === 'tables')     return <FaTable  className="text-teal-500" />
    if (node.folder === 'views')      return <FaEye    className="text-purple-500" />
    if (node.folder === 'procedures') return <FaCog    className="text-green-600" />
    if (node.folder === 'functions')  return <FaCode   className="text-orange-500" />
    return <FaColumns className="text-gray-400" />
  }

  const renderNode = (node: TreeNode, level = 0) => {
    const isExpanded = expandedNodes.has(node.id)
    const isChecked = selectedObjectIds.has(node.id)
    return (
      <div key={node.id}>
        <div
          className="group flex items-center gap-2 py-1 px-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
          style={{ paddingLeft: `${level * 16 + 8}px` }}
          onClick={() => handleNodeClick(node)}
          onContextMenu={(e) => { e.preventDefault(); setContextMenu({ show: true, x: e.clientX, y: e.clientY, node }) }}
        >
          {node.type === 'object' && (
            <input
              type="checkbox"
              className="h-4 w-4"
              checked={isChecked}
              onChange={(e) => toggleObjectSelection(node.id, e.target.checked)}
              onClick={(e) => e.stopPropagation()}
            />
          )}
          {getIcon(node)}
          <span className="text-sm flex-1 truncate">{node.label}</span>
          {node.type === 'object' && (
            <button
              title="Drop"
              className="opacity-0 group-hover:opacity-100 p-1 rounded hover:bg-red-100 dark:hover:bg-red-900 text-red-500 transition-opacity flex-shrink-0"
              onClick={(e) => { e.stopPropagation(); setDropConfirm({ node }) }}
            >
              <FaTrash className="text-xs" />
            </button>
          )}
        </div>
        {isExpanded && node.children && (
          <div>{node.children.map((c) => renderNode(c, level + 1))}</div>
        )}
      </div>
    )
  }

  const filteredTree = filterTree(treeData, filterText)

  // Context menu items per folder
  const ctxNode = contextMenu.node
  const isTableObj   = ctxNode?.type === 'object' && ctxNode.folder === 'tables'
  const isNativeObj  = ctxNode?.type === 'object' && ctxNode.folder !== 'tables'
  const isTablesDir  = ctxNode?.id === 'tables'
  const isViewsDir   = ctxNode?.id === 'views'
  const isProcsDir   = ctxNode?.id === 'procedures'
  const isFuncsDir   = ctxNode?.id === 'functions'
  const isFolderNode = ctxNode?.type === 'folder'

  return (
    <div className="flex-1 flex flex-col min-h-0">
      {/* Search + refresh */}
      <div className="p-2 border-b flex gap-2 flex-shrink-0">
        <input
          type="text"
          placeholder={translate('::App.Platform.Search')}
          value={filterText}
          onChange={(e) => setFilterText(e.target.value)}
          className="flex-1 px-3 py-1.5 text-sm border rounded-md bg-white dark:bg-gray-700 dark:border-gray-600"
        />
        <button
          onClick={loadObjects}
          disabled={loading || !dataSource}
          className="px-3 py-1.5 text-sm border rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-50"
          title={translate('::App.Platform.Refresh')}
        >
          <FaSyncAlt className={loading ? 'animate-spin' : ''} />
        </button>
      </div>

      {/* Tree */}
      <div className="flex-1 overflow-auto">
        {loading && <div className="text-center py-8 text-gray-500 text-sm">{translate('::App.Platform.Loading')}</div>}
        {!loading && treeData.length === 0 && <div className="text-center py-8 text-gray-500 text-sm">{translate('::App.Platform.NoDataSourceSelected')}</div>}
        {!loading && filteredTree.length > 0 && <div className="p-1">{filteredTree.map((n) => renderNode(n))}</div>}
        {!loading && treeData.length > 0 && filteredTree.length === 0 && <div className="text-center py-8 text-gray-500 text-sm">{translate('::App.Platform.NoResults')}</div>}
      </div>

      {/* Context menu */}
      {contextMenu.show && (
        <>
          <div className="fixed inset-0 z-40" onClick={closeCtx} />
          <div
            className="fixed z-50 bg-white dark:bg-gray-800 shadow-lg rounded border border-gray-200 dark:border-gray-700 py-1 min-w-[180px]"
            style={{ top: contextMenu.y, left: contextMenu.x }}
          >
            {/* TABLE object � Design */}
            {isTableObj && (
              <button
                className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                onClick={() => {
                  const t = ctxNode!.data as DatabaseTableDto
                  onGenerateTableScript?.(t.schemaName, t.tableName)
                  closeCtx()
                }}
              >
                <FaCode className="text-blue-600" /> Script olustur
              </button>
            )}

            {isTableObj && (
              <button
                className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                onClick={() => {
                  const t = ctxNode!.data as DatabaseTableDto
                  onDesignTable?.(t.schemaName, t.tableName)
                  closeCtx()
                }}
              >
                <FaTable className="text-teal-600" /> Design Table
              </button>
            )}

            {/* NATIVE object � View Definition */}
            {isNativeObj && (
              <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                onClick={() => {
                  const obj = ctxNode!.data as SqlNativeObjectDto
                  onViewDefinition?.(obj.schemaName, obj.objectName)
                  closeCtx()
                }}>
                {ctxNode!.folder === 'views'      && <FaEye   className="text-purple-500" />}
                {ctxNode!.folder === 'procedures' && <FaCog   className="text-green-600" />}
                {ctxNode!.folder === 'functions'  && <FaCode  className="text-orange-500" />}
                View Definition
              </button>
            )}

            {/* FOLDER � New ... */}
            {isTablesDir && (
              <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                onClick={() => { onNewTable?.(); closeCtx() }}>
                <FaPlus className="text-teal-600" /> New Table
              </button>
            )}
            {isViewsDir && (
              <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                onClick={() => { onTemplateSelect?.('', 'create-view'); closeCtx() }}>
                <FaPlus className="text-purple-500" /> New View
              </button>
            )}
            {isProcsDir && (
              <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                onClick={() => { onTemplateSelect?.('', 'create-procedure'); closeCtx() }}>
                <FaPlus className="text-green-600" /> New Stored Procedure
              </button>
            )}
            {isFuncsDir && (
              <>
                <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                  onClick={() => { onTemplateSelect?.('', 'create-scalar-function'); closeCtx() }}>
                  <FaPlus className="text-orange-500" /> New Scalar Function
                </button>
                <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                  onClick={() => { onTemplateSelect?.('', 'create-table-function'); closeCtx() }}>
                  <FaPlus className="text-orange-500" /> New Table-Valued Function
                </button>
              </>
            )}

            {/* Separator + Refresh for folders */}
            {isFolderNode && (
              <>
                <div className="my-1 border-t border-gray-100 dark:border-gray-700" />
                <button className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm flex items-center gap-2"
                  onClick={() => { loadObjects(); closeCtx() }}>
                  <FaSyncAlt /> {translate('::App.Platform.Refresh')}
                </button>
              </>
            )}
          </div>
        </>
      )}

      {/* Drop Confirm Dialog */}
      {dropConfirm && (
        <>
          <div className="fixed inset-0 z-50 bg-black/40 flex items-center justify-center" onClick={() => !dropping && setDropConfirm(null)}>
            <div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl p-6 max-w-sm w-full mx-4" onClick={(e) => e.stopPropagation()}>
              <div className="flex items-center gap-3 mb-3">
                <FaTrash className="text-red-500 text-lg flex-shrink-0" />
                <h6 className="font-semibold text-gray-900 dark:text-gray-100">Drop Object</h6>
              </div>
              <p className="text-sm text-gray-600 dark:text-gray-400 mb-1">
                The following object will be permanently dropped:
              </p>
              <code className="block text-sm bg-gray-100 dark:bg-gray-700 rounded px-3 py-2 mb-4 break-all">
                {buildDropSql(dropConfirm.node)}
              </code>
              <div className="flex justify-end gap-2">
                <button
                  disabled={dropping}
                  className="px-4 py-1.5 text-sm rounded border hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-50"
                  onClick={() => setDropConfirm(null)}
                >
                  Cancel
                </button>
                <button
                  disabled={dropping}
                  className="px-4 py-1.5 text-sm rounded bg-red-600 text-white hover:bg-red-700 disabled:opacity-50 flex items-center gap-2"
                  onClick={handleDrop}
                >
                  {dropping && <FaSyncAlt className="animate-spin text-xs" />}
                  Drop
                </button>
              </div>
            </div>
          </div>
        </>
      )}
    </div>
  )
}

export default SqlObjectExplorer
