import { useState, useEffect } from 'react'
import { Dialog, Button, Notification, toast } from '@/components/ui'
import {
  FaRegFolder,
  FaRegFolderOpen,
  FaRegFileAlt,
  FaCog,
  FaColumns,
  FaCode,
  FaSyncAlt,
  FaEdit,
  FaTrash,
  FaTable,
} from 'react-icons/fa'
import type { DataSourceDto } from '@/proxy/data-source'
import type {
  SqlFunctionDto,
  SqlQueryDto,
  SqlStoredProcedureDto,
  SqlViewDto,
  SqlObjectType,
} from '@/proxy/sql-query-manager/models'
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
import { useLocalization } from '@/utils/hooks/useLocalization'

export type SqlObject = SqlFunctionDto | SqlQueryDto | SqlStoredProcedureDto | SqlViewDto

interface TreeNode {
  id: string
  label: string
  type: 'root' | 'folder' | 'object' | 'column'
  objectType?: SqlObjectType
  data?: SqlObject | any
  children?: TreeNode[]
  expanded?: boolean
  isColumn?: boolean
  parentTable?: { schemaName: string; tableName: string }
}

interface SqlObjectExplorerProps {
  dataSource: DataSourceDto | null
  onObjectSelect: (object: SqlObject | null, objectType: SqlObjectType | null) => void
  selectedObject: SqlObject | null
  onTemplateSelect?: (template: string, templateType: string) => void
  onShowTableColumns?: (schemaName: string, tableName: string) => void
  refreshTrigger?: number
}

const SqlObjectExplorer = ({
  dataSource,
  onObjectSelect,
  selectedObject,
  onTemplateSelect,
  onShowTableColumns,
  refreshTrigger,
}: SqlObjectExplorerProps) => {
  const { translate } = useLocalization()
  const [treeData, setTreeData] = useState<TreeNode[]>([])
  const [expandedNodes, setExpandedNodes] = useState<Set<string>>(
    new Set(['root']), // Only root expanded by default
  )
  const [loading, setLoading] = useState(false)
  const [filterText, setFilterText] = useState('')
  const [contextMenu, setContextMenu] = useState<{
    show: boolean
    x: number
    y: number
    node: TreeNode | null
  }>({ show: false, x: 0, y: 0, node: null })
  const [showDeleteDialog, setShowDeleteDialog] = useState(false)
  const [objectToDelete, setObjectToDelete] = useState<{
    object: SqlObject
    type: SqlObjectType
  } | null>(null)

  useEffect(() => {
    if (dataSource) {
      loadObjects()
    } else {
      setTreeData([])
    }
  }, [dataSource, refreshTrigger]) // refreshTrigger değişince de yenile

  const loadObjects = async () => {
    if (!dataSource) return

    setLoading(true)
    try {
      // Single API call to get all objects
      const response = await sqlObjectManagerService.getAllObjects(dataSource.code || '')
      const allObjects = response.data

      const tree: TreeNode[] = [
        {
          id: 'root',
          label: dataSource.code || 'Database',
          type: 'root',
          expanded: true,
          children: [
            {
              id: 'templates',
              label: translate('::App.Platform.Templates'),
              type: 'folder',
              expanded: expandedNodes.has('templates'),
              children: [
                {
                  id: 'template-select',
                  label: 'SELECT Query',
                  type: 'object' as const,
                  data: { templateType: 'select' } as any,
                },
                {
                  id: 'template-insert',
                  label: 'INSERT Query',
                  type: 'object' as const,
                  data: { templateType: 'insert' } as any,
                },
                {
                  id: 'template-update',
                  label: 'UPDATE Query',
                  type: 'object' as const,
                  data: { templateType: 'update' } as any,
                },
                {
                  id: 'template-delete',
                  label: 'DELETE Query',
                  type: 'object' as const,
                  data: { templateType: 'delete' } as any,
                },
                {
                  id: 'template-sp',
                  label: 'Stored Procedure',
                  type: 'object' as const,
                  data: { templateType: 'create-procedure' } as any,
                },
                {
                  id: 'template-view',
                  label: 'View',
                  type: 'object' as const,
                  data: { templateType: 'create-view' } as any,
                },
                {
                  id: 'template-scalar-function',
                  label: 'Scalar Function',
                  type: 'object' as const,
                  data: { templateType: 'create-scalar-function' } as any,
                },
                {
                  id: 'template-table-function',
                  label: 'Table-Valued Function',
                  type: 'object' as const,
                  data: { templateType: 'create-table-function' } as any,
                },
              ],
            },
            {
              id: 'tables',
              label: `${translate('::App.Platform.Tables')} (${allObjects.tables.length})`,
              type: 'folder',
              expanded: expandedNodes.has('tables'),
              children:
                allObjects.tables.map((t) => ({
                  id: `table-${t.schemaName}-${t.tableName}`,
                  label: t.fullName,
                  type: 'object' as const,
                  data: t,
                })) || [],
            },
            {
              id: 'queries',
              label: `${translate('::App.Platform.Queries')} (${allObjects.queries.length})`,
              type: 'folder',
              objectType: 1,
              expanded: expandedNodes.has('queries'),
              children:
                allObjects.queries.map((q) => ({
                  id: q.id || '',
                  label: q.name,
                  type: 'object' as const,
                  objectType: 1 as SqlObjectType,
                  data: q,
                })) || [],
            },
            {
              id: 'procedures',
              label: `${translate('::App.Platform.StoredProcedures')} (${allObjects.storedProcedures.length})`,
              type: 'folder',
              objectType: 2,
              expanded: expandedNodes.has('procedures'),
              children:
                allObjects.storedProcedures.map((p) => {
                  const deployInfo = p.isDeployed && p.lastDeployedAt 
                    ? ` (${new Date(p.lastDeployedAt).toLocaleString('tr-TR', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })})`
                    : '';
                  return {
                    id: p.id || '',
                    label: `${p.displayName || p.procedureName}${p.isDeployed ? ' ✅' : ' ❌'}${deployInfo}`,
                    type: 'object' as const,
                    objectType: 2 as SqlObjectType,
                    data: p,
                  };
                }) || [],
            },
            {
              id: 'views',
              label: `${translate('::App.Platform.Views')} (${allObjects.views.length})`,
              type: 'folder',
              objectType: 3,
              expanded: expandedNodes.has('views'),
              children:
                allObjects.views.map((v) => {
                  const deployInfo = v.isDeployed && v.lastDeployedAt 
                    ? ` (${new Date(v.lastDeployedAt).toLocaleString('tr-TR', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })})`
                    : '';
                  return {
                    id: v.id || '',
                    label: `${v.displayName || v.viewName}${v.isDeployed ? ' ✅' : ' ❌'}${deployInfo}`,
                    type: 'object' as const,
                    objectType: 3 as SqlObjectType,
                    data: v,
                  };
                }) || [],
            },
            {
              id: 'functions',
              label: `${translate('::App.Platform.Functions')} (${allObjects.functions.length})`,
              type: 'folder',
              objectType: 4,
              expanded: expandedNodes.has('functions'),
              children:
                allObjects.functions.map((f) => {
                  const deployInfo = f.isDeployed && f.lastDeployedAt 
                    ? ` (${new Date(f.lastDeployedAt).toLocaleString('tr-TR', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })})`
                    : '';
                  return {
                    id: f.id || '',
                    label: `${f.displayName || f.functionName}${f.isDeployed ? ' ✅' : ' ❌'}${deployInfo}`,
                    type: 'object' as const,
                    objectType: 4 as SqlObjectType,
                    data: f,
                  };
                }) || [],
            },
          ],
        },
      ]

      setTreeData(tree)
    } catch (error: any) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message || translate('::App.Platform.FailedToLoadObjects')}
        </Notification>,
        { placement: 'top-center' },
      )
    } finally {
      setLoading(false)
    }
  }

  const loadTableColumns = async (schemaName: string, tableName: string): Promise<TreeNode[]> => {
    try {
      const response = await sqlObjectManagerService.getTableColumns(
        dataSource?.code || '',
        schemaName,
        tableName,
      )
      return response.data.map((col) => ({
        id: `column-${schemaName}-${tableName}-${col.columnName}`,
        label: `${col.columnName} (${col.dataType}${col.maxLength ? `(${col.maxLength})` : ''})${col.isNullable ? '' : ' NOT NULL'}`,
        type: 'column' as const,
        isColumn: true,
        data: col,
        parentTable: { schemaName, tableName },
      }))
    } catch (error) {
      return []
    }
  }

  const toggleNode = async (nodeId: string) => {
    const newSet = new Set(expandedNodes)

    if (newSet.has(nodeId)) {
      newSet.delete(nodeId)
      setExpandedNodes(newSet)
    } else {
      newSet.add(nodeId)
      setExpandedNodes(newSet)

      // If it's a table node and hasn't loaded columns yet, load them
      if (nodeId.startsWith('table-') && dataSource) {
        const tableNode = findNodeById(treeData, nodeId)
        if (tableNode && (!tableNode.children || tableNode.children.length === 0)) {
          const tableData = tableNode.data as any
          const columns = await loadTableColumns(tableData.schemaName, tableData.tableName)

          // Update tree data with columns
          setTreeData((prevTree) => {
            return updateNodeChildren(prevTree, nodeId, columns)
          })
        }
      }
    }
  }

  const findNodeById = (nodes: TreeNode[], id: string): TreeNode | null => {
    for (const node of nodes) {
      if (node.id === id) return node
      if (node.children) {
        const found = findNodeById(node.children, id)
        if (found) return found
      }
    }
    return null
  }

  const updateNodeChildren = (
    nodes: TreeNode[],
    nodeId: string,
    children: TreeNode[],
  ): TreeNode[] => {
    return nodes.map((node) => {
      if (node.id === nodeId) {
        return { ...node, children }
      }
      if (node.children) {
        return { ...node, children: updateNodeChildren(node.children, nodeId, children) }
      }
      return node
    })
  }

  const filterTree = (nodes: TreeNode[], searchText: string): TreeNode[] => {
    if (!searchText.trim()) return nodes

    const search = searchText.toLowerCase()
    const filtered = nodes
      .map((node) => {
        const matchesSearch = node.label.toLowerCase().includes(search)
        const filteredChildren = node.children ? filterTree(node.children, searchText) : []

        if (matchesSearch || filteredChildren.length > 0) {
          return {
            ...node,
            children: filteredChildren.length > 0 ? filteredChildren : node.children,
          } as TreeNode
        }
        return null
      })
      .filter((node) => node !== null) as TreeNode[]

    return filtered
  }

  const handleNodeClick = (node: TreeNode) => {
    if (node.type === 'folder' || node.type === 'root') {
      toggleNode(node.id)
    } else if (node.type === 'column') {
      // Column clicked - do nothing or show info
      return
    } else if (node.type === 'object' && node.data) {
      // Check if it's a template
      if ((node.data as any).templateType && onTemplateSelect) {
        const templateType = (node.data as any).templateType
        onTemplateSelect('', templateType) // Template content will be generated in parent
      }
      // Check if it's a table
      else if (node.id.startsWith('table-') && onTemplateSelect) {
        const table = node.data as any
        const selectQuery = `-- SELECT from ${table.fullName || table.tableName}\nSELECT * \nFROM ${table.fullName || `[${table.schemaName}].[${table.tableName}]`}\nWHERE 1=1;`
        onTemplateSelect(selectQuery, 'table-select')
      } else if (node.objectType) {
        onObjectSelect(node.data, node.objectType)
      }
    }
  }

  const handleContextMenu = (e: React.MouseEvent, node: TreeNode) => {
    e.preventDefault()

    // Don't show context menu for columns or templates
    if (node.type === 'column' || node.id.startsWith('template-')) {
      return
    }

    setContextMenu({
      show: true,
      x: e.clientX,
      y: e.clientY,
      node,
    })
  }

  const handleDelete = async () => {
    if (!objectToDelete || !objectToDelete.object.id) return

    try {
      const { object, type } = objectToDelete

      switch (type) {
        case 1:
          await sqlObjectManagerService.deleteQuery(object.id!)
          break
        case 2:
          await sqlObjectManagerService.deleteStoredProcedure(object.id!)
          break
        case 3:
          await sqlObjectManagerService.deleteView(object.id!)
          break
        case 4:
          await sqlObjectManagerService.deleteFunction(object.id!)
          break
      }

      toast.push(
        <Notification type="success" title={translate('::App.Platform.Success')}>
          {translate('::App.Platform.ObjectDeletedSuccessfully')}
        </Notification>,
        { placement: 'top-center' },
      )

      setShowDeleteDialog(false)
      setObjectToDelete(null)
      loadObjects()

      if (selectedObject?.id === object.id) {
        onObjectSelect(null, null)
      }
    } catch (error: any) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message || translate('::App.Platform.FailedToDeleteObject')}
        </Notification>,
        { placement: 'top-center' },
      )
    }
  }

  const getIcon = (node: TreeNode) => {
    if (node.type === 'root') return <FaRegFolder className="text-blue-500" />

    if (node.type === 'folder') {
      const isExpanded = expandedNodes.has(node.id)

      // Templates folder
      if (node.id === 'templates')
        return isExpanded ? (
          <FaRegFolderOpen className="text-orange-500" />
        ) : (
          <FaRegFolder className="text-orange-500" />
        )

      // Tables folder
      if (node.id === 'tables')
        return isExpanded ? (
          <FaRegFolderOpen className="text-blue-500" />
        ) : (
          <FaRegFolder className="text-blue-500" />
        )

      if (node.objectType === 1)
        return isExpanded ? (
          <FaRegFolderOpen className="text-yellow-500" />
        ) : (
          <FaRegFolder className="text-yellow-500" />
        )

      if (node.objectType === 2)
        return isExpanded ? (
          <FaRegFolderOpen className="text-green-500" />
        ) : (
          <FaRegFolder className="text-green-500" />
        )

      if (node.objectType === 3)
        return isExpanded ? (
          <FaRegFolderOpen className="text-purple-500" />
        ) : (
          <FaRegFolder className="text-purple-500" />
        )

      if (node.objectType === 4)
        return isExpanded ? (
          <FaRegFolderOpen className="text-red-500" />
        ) : (
          <FaRegFolder className="text-red-500" />
        )
    }

    if (node.type === 'object') {
      // Check if it's a template
      if ((node.data as any)?.templateType) {
        return <FaCode className="text-orange-500" />
      }

      // Check if it's a table
      if (node.id.startsWith('table-')) {
        return <FaTable className="text-blue-500" />
      }

      if (node.objectType === 1) return <FaRegFileAlt className="text-gray-500" />
      if (node.objectType === 2) return <FaCog className="text-gray-500" />
      if (node.objectType === 3) return <FaColumns className="text-gray-500" />
      if (node.objectType === 4) return <FaCode className="text-gray-500" />
    }

    if (node.type === 'column') {
      return <FaColumns className="text-gray-400 text-sm" />
    }

    return <FaRegFolder />
  }

  const renderNode = (node: TreeNode, level = 0) => {
    const isExpanded = expandedNodes.has(node.id)
    const isSelected = node.type === 'object' && selectedObject?.id === node.id
    const isColumn = node.type === 'column'

    return (
      <div key={node.id}>
        <div
          className={`flex items-center gap-2 py-1 px-2 ${isColumn ? 'cursor-default' : 'cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700'} rounded ${
            isSelected ? 'bg-blue-100 dark:bg-blue-900' : ''
          }`}
          style={{ paddingLeft: `${level * 16 + 8}px` }}
          onClick={() => !isColumn && handleNodeClick(node)}
          onContextMenu={(e) => !isColumn && handleContextMenu(e, node)}
        >
          {getIcon(node)}
          <span className={`text-sm flex-1 ${isColumn ? 'text-gray-600 dark:text-gray-400' : ''}`}>
            {node.label}
          </span>
        </div>

        {isExpanded && node.children && (
          <div>{node.children.map((child) => renderNode(child, level + 1))}</div>
        )}
      </div>
    )
  }

  const filteredTree = filterTree(treeData, filterText)

  return (
    <div className="h-full flex flex-col">
      {/* Filter and Refresh Controls */}
      <div className="p-2 border-b space-y-2 flex-shrink-0">
        <div className="flex gap-2">
          <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>
      </div>

      {/* Tree Content */}
      <div className="h-[calc(100vh-265px)] overflow-auto">
        {loading && (
          <div className="text-center py-8 text-gray-500">
            {translate('::App.Platform.Loading')}
          </div>
        )}
        {!loading && treeData.length === 0 && (
          <div className="text-center py-8 text-gray-500">
            {translate('::App.Platform.NoDataSourceSelected')}
          </div>
        )}
        {!loading && filteredTree.length > 0 && (
          <div className="space-y-1 p-2">{filteredTree.map((node) => renderNode(node))}</div>
        )}
        {!loading && treeData.length > 0 && filteredTree.length === 0 && (
          <div className="text-center py-8 text-gray-500">
            {translate('::App.Platform.NoResultsFound')}
          </div>
        )}
      </div>

      {contextMenu.show && (
        <>
          <div
            className="fixed inset-0 z-40"
            onClick={() => setContextMenu({ show: false, x: 0, y: 0, node: null })}
          />
            <div
              className="fixed z-50 bg-white dark:bg-gray-800 shadow-lg rounded border border-gray-200 dark:border-gray-700 py-1"
              style={{ top: contextMenu.y, left: contextMenu.x }}
            >
              {contextMenu.node?.type === 'object' && !contextMenu.node?.id?.startsWith('table-') && (
                <>
                  <button
                    className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm"
                    onClick={() => {
                      if (contextMenu.node?.data && contextMenu.node?.objectType) {
                        onObjectSelect(contextMenu.node.data, contextMenu.node.objectType)
                      }
                      setContextMenu({ show: false, x: 0, y: 0, node: null })
                    }}
                  >
                    <FaEdit className="inline mr-2" />
                    {translate('::App.Platform.Edit')}
                  </button>

                  <button
                    className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm text-red-600"
                    onClick={() => {
                      if (contextMenu.node?.data && contextMenu.node?.objectType) {
                        setObjectToDelete({
                          object: contextMenu.node.data,
                          type: contextMenu.node.objectType,
                        })
                        setShowDeleteDialog(true)
                      }
                      setContextMenu({ show: false, x: 0, y: 0, node: null })
                    }}
                  >
                    <FaTrash className="inline mr-2" />
                    {translate('::App.Platform.Delete')}
                  </button>
                </>
              )}

              {contextMenu.node?.type === 'folder' && (
                <button
                  className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm"
                  onClick={() => {
                    loadObjects()
                    setContextMenu({ show: false, x: 0, y: 0, node: null })
                  }}
                >
                  <FaSyncAlt className="inline mr-2" />
                  {translate('::App.Platform.Refresh')}
                </button>
              )}

              {contextMenu.node?.id?.startsWith('table-') && contextMenu.node?.data && (
                <button
                  className="w-full px-4 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 text-sm"
                  onClick={() => {
                    if (onShowTableColumns && contextMenu.node?.data) {
                      onShowTableColumns(
                        contextMenu.node.data.schemaName,
                        contextMenu.node.data.tableName
                      )
                    }
                    setContextMenu({ show: false, x: 0, y: 0, node: null })
                  }}
                >
                  <FaColumns className="inline mr-2" />
                  {translate('::App.Platform.ShowColumns')}
                </button>
              )}
            </div>
        </>
      )}

      <Dialog
        isOpen={showDeleteDialog}
        onClose={() => setShowDeleteDialog(false)}
        onRequestClose={() => setShowDeleteDialog(false)}
      >
        <h5 className="mb-4">{translate('::App.Platform.ConfirmDelete')}</h5>
        <p className="mb-4">{translate('::App.Platform.DeleteConfirmationMessage')}</p>
        <div className="flex justify-end gap-2">
          <Button variant="plain" onClick={() => setShowDeleteDialog(false)}>
            {translate('::App.Platform.Cancel')}
          </Button>
          <Button variant="solid" onClick={handleDelete}>
            {translate('::App.Platform.DeleteAction')}
          </Button>
        </div>
      </Dialog>
    </div>
  )
}

export default SqlObjectExplorer
