import { useState, useEffect, useCallback } from 'react'
import { FaThLarge } from 'react-icons/fa'
import {
  parseReactCode,
  updateComponentProp,
  updateComponentProps,
  generateHookCode,
  generateHookVariableName,
  removeHookFromCode,
  generateUniqueId,
  removeComponentAndHooksFromCode,
  generateComponentJSX,
  insertJSXAtPosition,
} from '../../utils/codeParser'
import { ComponentLibrary } from '../../components/codeLayout/ComponentLibrary'
import { Splitter } from '../../components/codeLayout/Splitter'
import { PanelManager } from '../../components/codeLayout/PanelManager'
import { CodeEditor } from '../../components/codeLayout/CodeEditor'
import { ComponentDefinition, ComponentInfo, EditorState } from '../../proxy/developerKit/componentInfo'
import PropertyPanel from '../../components/codeLayout/PropertyPanel'
import ComponentSelector from '../../components/codeLayout/ComponentSelector'
import { useParams } from 'react-router-dom'
import { useComponents } from '../../contexts/ComponentContext'
import { toast } from '../../components/ui'
import Notification from '../../components/ui/Notification/Notification'
import { PanelState } from '../../components/codeLayout/data/componentDefinitions'

const INITIAL_CODE = `const Component = () => {
  return (
    <>
    </>
  );
};

export default Component
`

function CodeLayout() {
  const { id } = useParams()
  const { getComponent, updateComponent } = useComponents()
  const [showPanelManager, setShowPanelManager] = useState(false)
  const [panelState, setPanelState] = useState<PanelState>({
    toolbox: true,
    properties: true,
  })
  const [editorState, setEditorState] = useState<EditorState>({
    code: INITIAL_CODE,
    components: [],
    selectedComponentId: null,
  })

  const isEditing = !!id
  const [code, setCode] = useState<string>(INITIAL_CODE)
  const [hasCodeChanges, setHasCodeChanges] = useState(false)
  const [isLoaded, setIsLoaded] = useState(false)
  const [name, setName] = useState('')
  const [dependencies, setDependencies] = useState<string[]>([])
  const [isActive, setIsActive] = useState(true)

  const handleSave = async () => {
    try {
      const componentData = {
        name: name.trim(),
        dependencies: JSON.stringify(dependencies), // Serialize dependencies to JSON string
        code: code.trim(),
        isActive,
      }

      if (isEditing && id) {
        updateComponent(id, componentData)
        parseAndUpdateComponents(componentData.code)
      }
    } catch (error) {
      console.error('Error saving component:', error)
      alert('Failed to save component. Please try again.')
    } finally {
      setHasCodeChanges(false)
      setIsLoaded(true)

      toast.push(
        <Notification type="success" duration={2000}>
          "Bileşen başarıyla kaydedildi."
        </Notification>,
        {
          placement: 'top-end',
        },
      )
    }
  }

  // Load existing component data - sadece edit modunda
  useEffect(() => {
    if (isEditing && id && !isLoaded) {
      const component = getComponent(id)
      if (component) {
        setName(component.name)
        // setDescription(component.description || "");
        // Parse dependencies from JSON string
        try {
          const deps = component.dependencies ? JSON.parse(component.dependencies) : []
          setDependencies(Array.isArray(deps) ? deps : [])
        } catch {
          setDependencies([])
        }
        setCode(component.code) // Mevcut kodu yükle
        // Parse components from the loaded code
        parseAndUpdateComponents(component.code)
        setIsActive(component.isActive)
        setIsLoaded(true)
      }
    } else if (!isEditing && !isLoaded) {
      // Yeni komponent için boş başla - TEMPLATE YOK
      setIsLoaded(true)
    }
  }, [id, isEditing, getComponent, isLoaded])

  // NEW: Handle drop to Code Editor instead of Canvas
  const handleDropToCodeEditor = (
    componentDef: ComponentDefinition,
    position: { line: number; column: number },
  ): void => {
    if (!componentDef || typeof componentDef !== 'object') {
      console.error('Component definition is null or undefined')
      return
    }
    if (!componentDef.name) {
      console.error('Invalid component definition in handleDropToCodeEditor')
      return
    }

    const propertiesObj: Record<string, any> = {}
    if (Array.isArray(componentDef.properties)) {
      componentDef.properties.forEach((prop) => {
        propertiesObj[prop.name] = prop
      })
    }
    const newComponent: ComponentInfo = {
      id: generateUniqueId(),
      type: componentDef.name, // type alanı componentDef.name olmalı
      props: propertiesObj,
      name: componentDef.name,
      startLine: 0,
      endLine: 0,
      startColumn: 0,
      endColumn: 0,
    }

    // Generate JSX string for this component
    const componentJSX = generateComponentJSX(newComponent)

    // Insert the JSX at the cursor position in the code editor
    setCode(insertJSXAtPosition(code, componentJSX, position))
  }

  const handleAppDragOver = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
  }

  const parseAndUpdateComponents = useCallback((code: string) => {
    try {
      const parsed = parseReactCode(code)
      setEditorState((prev) => ({
        ...prev,
        code,
        components: parsed.components,
      }))
    } catch (error) {
      const msg = error instanceof Error ? error.message : 'Koddan komponentler parse edilemedi.'
      console.log('Parse error:', msg)
      setEditorState((prev) => ({
        ...prev,
        code, // Only update the code, keep existing components
      }))
    }
  }, [])

  // Handle code changes from Monaco Editor
  const handleCodeChange = useCallback(
    (value: string | undefined) => {
      if (value !== undefined) {
        setCode(value)
        setHasCodeChanges(value !== editorState.code)
      }
    },
    [editorState.code],
  )

  // Apply code changes
  const handleApplyCodeChanges = useCallback(() => {
    parseAndUpdateComponents(code)
    setHasCodeChanges(false)
  }, [parseAndUpdateComponents, code])

  // Reset code changes
  const handleResetCodeChanges = useCallback(() => {
    setCode(editorState.code)
    setHasCodeChanges(false)
  }, [editorState.code])

  // Handle property changes from Property Panel
  // Handle hook toggle
  const handleHookToggle = useCallback(
    (componentId: string, hookType: string, enabled: boolean) => {
      console.log('🪝 App: handleHookToggle called:', {
        componentId,
        hookType,
        enabled,
      })
      const selectedComponent = editorState.components?.find((c) => c.id === componentId)
      if (!selectedComponent) return

      // Use the most up-to-date code (pendingCode if available, otherwise editorState.code)
      let updatedCode = code || editorState.code
      console.log('🔍 App: Using code source:', code === editorState.code ? 'same' : 'pendingCode')

      if (enabled) {
        // Check if hook is already present - more specific check
        const varName = generateHookVariableName(hookType, componentId)
        console.log('🔍 App: Checking for existing hook variable:', varName)

        // Create a more specific regex to check for actual hook declarations
        const hookDeclarationRegex = new RegExp(
          `const\\s+(?:\\[.*?${varName}.*?\\]|${varName})\\s*=\\s*${hookType}\\s*\\(`,
        )
        if (hookDeclarationRegex.test(updatedCode)) {
          console.log('⚠️ App: Hook already exists, skipping')
          return // Hook already exists
        }

        // Handle React imports - improved approach
        const reactImportRegex = /^import\s+\{([^}]*)\}\s+from\s+['"]react['"]\s*;?/m
        const reactMatch = reactImportRegex.exec(updatedCode)

        if (reactMatch) {
          // reactMatch[1] --> süslü parantez içi örn: "useState, useRef"
          let existingHooks = reactMatch[1]
            .split(',')
            .map((h) => h.trim())
            .filter((h) => h)

          // Eğer hookType yoksa ekle
          if (!existingHooks.includes(hookType)) {
            existingHooks.push(hookType)
          }

          // Tekrarları kaldır (güvenlik için)
          existingHooks = [...new Set(existingHooks)]

          const newImport = `import { ${existingHooks.join(', ')} } from 'react';\n`
          updatedCode = updatedCode.replace(reactImportRegex, newImport)

          console.log('🔄 App: Updated existing React import:', newImport.trim())
        } else {
          // React import satırı yoksa ekle
          const importLine = `import { ${hookType} } from 'react';\n\n`
          updatedCode = importLine + updatedCode
          console.log('🔄 App: Added new React import:', importLine.trim())
        }

        // Add hook declaration
        const hookCode = generateHookCode(hookType, componentId, selectedComponent.type)
        console.log('🔍 App: Generated hook code:', hookCode)

        // Try multiple patterns for function declaration
        const functionPatterns = [
          /function\s+Component\s*\([^)]*\)\s*\{/, // function Component() {
          /function\s+\w+\s*\([^)]*\)\s*\{/, // function AnyName() {
          /const\s+\w+\s*=\s*\([^)]*\)\s*=>\s*\{/, // const Component = () => {
          /export\s+default\s+function\s*\([^)]*\)\s*\{/, // export default function() {
        ]

        let match2 = null
        for (const pattern of functionPatterns) {
          match2 = updatedCode.match(pattern)
          if (match2) {
            console.log('🔍 App: Found function with pattern:', pattern)
            break
          }
        }

        console.log('🔍 App: Function match result:', match2)
        console.log('🔍 App: Updated code preview:', updatedCode.substring(0, 500))

        if (match2 && typeof match2.index === 'number') {
          const insertPosition = match2.index + match2[0].length
          updatedCode =
            updatedCode.slice(0, insertPosition) +
            '\n  ' +
            hookCode +
            '\n' +
            updatedCode.slice(insertPosition)
          console.log('✅ App: Hook code inserted successfully')
        } else {
          console.log('⚠️ App: Could not find function body to insert hook')
          // Fallback: insert after the first opening brace
          const firstBrace = updatedCode.indexOf('{')
          if (firstBrace !== -1) {
            updatedCode =
              updatedCode.slice(0, firstBrace + 1) +
              '\n  ' +
              hookCode +
              '\n' +
              updatedCode.slice(firstBrace + 1)
            console.log('✅ App: Hook code inserted using fallback method')
          }
        }

        // Update component properties if needed
        if (hookType === 'useState') {
          const setterName = `set${varName.charAt(0).toUpperCase() + varName.slice(1)}`

          // Update component props based on type
          if (selectedComponent.type === 'input') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'value', `{${varName}}`)
            updatedCode = updateComponentProp(
              updatedCode,
              componentId,
              'onChange',
              `{(e) => ${setterName}(e.target.value)}`,
            )
          } else if (selectedComponent.type === 'button') {
            updatedCode = updateComponentProp(
              updatedCode,
              componentId,
              'onClick',
              `{() => ${setterName}(!${varName})}`,
            )
          } else if (selectedComponent.type === 'checkbox') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'checked', `{${varName}}`)
            updatedCode = updateComponentProp(
              updatedCode,
              componentId,
              'onChange',
              `{(val) => ${setterName}(val)}`,
            )
          }
        } else if (hookType === 'useRef') {
          updatedCode = updateComponentProp(updatedCode, componentId, 'ref', `{${varName}}`)
        }
      } else {
        // Remove hook
        updatedCode = removeHookFromCode(updatedCode, hookType, componentId)

        // Remove related props
        if (hookType === 'useState') {
          if (selectedComponent.type === 'input') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'value', '')
            updatedCode = updateComponentProp(updatedCode, componentId, 'onChange', null)
          } else if (selectedComponent.type === 'button') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'onClick', null)
          } else if (selectedComponent.type === 'checkbox') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'checked', false)
            updatedCode = updateComponentProp(updatedCode, componentId, 'onChange', null)
          }
        } else if (hookType === 'useRef') {
          updatedCode = updateComponentProp(updatedCode, componentId, 'ref', null)
        }
      }

      setEditorState((prev) => {
        console.log('🔄 App: Final updatedCode before parsing:', updatedCode)
        const parsed = parseReactCode(updatedCode)
        console.log('🔄 App: Parsed components:', parsed.components?.length)
        const newState = {
          code: updatedCode,
          components: parsed.components,
          selectedComponentId: prev.selectedComponentId, // Preserve selection
        }
        console.log('🔄 App: New editor state code preview:', newState.code.substring(0, 300))
        return newState
      })

      // Also update pending code to match
      setCode(updatedCode)
    },
    [editorState.code, editorState.components, code],
  )

  // Zincirleme hook güncelleme fonksiyonu
  const applyMultipleHookToggles = (
    toggles: { componentId: string; hookType: string; enabled: boolean }[],
  ) => {
    let updatedCode = code || editorState.code
    // 1. Sadece kaldırılması gereken hook'ları kaldır
    toggles
      .filter((t) => t.enabled === false)
      .forEach(({ hookType, componentId }) => {
        const selectedComponent = editorState.components?.find((c) => c.id === componentId)
        if (!selectedComponent) return
        updatedCode = removeHookFromCode(updatedCode, hookType, componentId)
        // Prop temizliği
        if (hookType === 'useState') {
          if (selectedComponent.type === 'input') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'value', '')
            updatedCode = updateComponentProp(updatedCode, componentId, 'onChange', null)
          } else if (selectedComponent.type === 'button') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'onClick', null)
          } else if (selectedComponent.type === 'checkbox') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'checked', false)
            updatedCode = updateComponentProp(updatedCode, componentId, 'onChange', null)
          }
        } else if (hookType === 'useRef') {
          updatedCode = updateComponentProp(updatedCode, componentId, 'ref', null)
        }
      })
    // 2. Eklenmesi gereken hook'ları ekle (veya zaten varsa dokunma)
    toggles
      .filter((t) => t.enabled === true)
      .forEach(({ hookType, componentId }) => {
        const selectedComponent = editorState.components?.find((c) => c.id === componentId)
        if (!selectedComponent) return
        const varName = generateHookVariableName(hookType, componentId)
        // Hook kodu fonksiyon gövdesinde yoksa ekle
        const hookDeclarationRegex = new RegExp(
          `const\\s+(?:\\[.*?${varName}.*?\\]|${varName})\\s*=\\s*${hookType}\\s*\\(`,
        )
        if (!hookDeclarationRegex.test(updatedCode)) {
          const reactImportRegex =
            // eslint-disable-next-line no-useless-escape
            /import\\s+React(?:\\s*,\\s*\\{([^}]*)\\})?\\s+from\\s+['\"]react['\"];?/
          const importMatch = updatedCode.match(reactImportRegex)
          const allHooks = new Set<string>()
          if (importMatch && importMatch[1]) {
            importMatch[1]
              .split(',')
              .map((h) => h.trim())
              .filter((h) => h)
              .forEach((h) => allHooks.add(h))
          }
          allHooks.add(hookType)
          let newImport = ''
          if (allHooks.size > 0) {
            newImport = `import { ${Array.from(allHooks).join(', ')} } from 'react';\n`
          }
          if (importMatch) {
            updatedCode = updatedCode.replace(reactImportRegex, newImport)
          } else {
            updatedCode = newImport + updatedCode
          }
          // Hook kodunu fonksiyon gövdesine ekle
          const hookCode = generateHookCode(hookType, componentId, selectedComponent.type)
          const functionPatterns = [
            /function\s+Component\s*\([^)]*\)\s*\{/, // function Component() {
            /function\s+\w+\s*\([^)]*\)\s*\{/, // function AnyName() {
            /const\s+\w+\s*=\s*\([^)]*\)\s*=>\s*\{/, // const Component = () => {
            /export\s+default\s+function\s*\([^)]*\)\s*\{/, // export default function() {
          ]
          let match2 = null
          for (const pattern of functionPatterns) {
            match2 = updatedCode.match(pattern)
            if (match2) break
          }
          if (match2 && typeof match2.index === 'number') {
            const insertPosition = match2.index + match2[0].length
            updatedCode =
              updatedCode.slice(0, insertPosition) +
              '\n  ' +
              hookCode +
              '\n' +
              updatedCode.slice(insertPosition)
          } else {
            const firstBrace = updatedCode.indexOf('{')
            if (firstBrace !== -1) {
              updatedCode =
                updatedCode.slice(0, firstBrace + 1) +
                '\n  ' +
                hookCode +
                '\n' +
                updatedCode.slice(firstBrace + 1)
            }
          }
        }
        // Prop güncellemeleri
        if (hookType === 'useState') {
          const setterName = `set${varName.charAt(0).toUpperCase() + varName.slice(1)}`
          if (selectedComponent.type === 'input') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'value', `{${varName}}`)
            updatedCode = updateComponentProp(
              updatedCode,
              componentId,
              'onChange',
              `{(e) => ${setterName}(e.target.value)}`,
            )
          } else if (selectedComponent.type === 'button') {
            updatedCode = updateComponentProp(
              updatedCode,
              componentId,
              'onClick',
              `{() => ${setterName}(!${varName})}`,
            )
          } else if (selectedComponent.type === 'checkbox') {
            updatedCode = updateComponentProp(updatedCode, componentId, 'checked', `{${varName}}`)
            updatedCode = updateComponentProp(
              updatedCode,
              componentId,
              'onChange',
              `{(e) => ${setterName}(e.target.checked)}`,
            )
          }
        } else if (hookType === 'useRef') {
          updatedCode = updateComponentProp(updatedCode, componentId, 'ref', `{${varName}}`)
        }
      })
    setEditorState((prev) => {
      const parsed = parseReactCode(updatedCode)
      return {
        code: updatedCode,
        components: parsed.components,
        selectedComponentId: prev.selectedComponentId,
      }
    })
    setCode(updatedCode)
  }

  // Handle multiple property changes at once
  const handlePropertiesChange = useCallback(
    (componentId: string, updates: Record<string, any>) => {
      console.log('🔄 App: handlePropertiesChange called:', {
        componentId,
        updates,
      })

      const updatedCode = updateComponentProps(editorState.code, componentId, updates)
      console.log('📝 App: Properties updated, code changed:', editorState.code !== updatedCode)

      setEditorState((prev) => {
        const parsed = parseReactCode(updatedCode)
        return {
          code: updatedCode,
          components: parsed.components,
          selectedComponentId: prev.selectedComponentId, // Preserve selection
        }
      })

      // Update pending code to reflect changes
      setCode(updatedCode)
    },
    [editorState.code],
  )

  // Handle component list refresh
  const handleRefreshComponents = useCallback(() => {
    parseAndUpdateComponents(editorState.code)
  }, [parseAndUpdateComponents, editorState.code])

  // Handle component selection
  const handleSelectComponent = useCallback((componentId: string | null) => {
    setEditorState((prev) => ({
      ...prev,
      selectedComponentId: componentId,
    }))
  }, [])

  // Initialize parsing on mount
  useEffect(() => {
    parseAndUpdateComponents(INITIAL_CODE)
  }, [parseAndUpdateComponents])

  const handleDragStart = (_componentDef: ComponentDefinition, e: React.DragEvent) => {
    e.stopPropagation()
  }

  const selectedComponent =
    editorState.components?.find((c) => c.id === editorState.selectedComponentId) || null

  const renderLeftPanel = () => {
    if (!panelState.toolbox) return null
    return <ComponentLibrary onDragStart={handleDragStart} />
  }

  // Komponent ve ilgili hook'ları koddan silen fonksiyon
  const handleDeleteComponent = (componentId: string) => {
    // Koddan JSX ve hook'ları sil
    const updatedCode = removeComponentAndHooksFromCode(code, componentId)
    // Koddan parse edip state'i güncelle
    parseAndUpdateComponents(updatedCode)
    setCode(updatedCode)
    // Seçili komponenti kaldır
    setEditorState((prev) => ({
      ...prev,
      selectedComponentId: null,
    }))
  }

  const renderRightPanel = () => {
    if (!panelState.properties) return null

    return (
      <div className="flex flex-col flex-1 min-h-0 h-full w-full">
        <ComponentSelector
          components={editorState.components}
          selectedComponentId={editorState.selectedComponentId}
          onSelectComponent={handleSelectComponent}
          onRefresh={handleRefreshComponents}
        />

        <PropertyPanel
          selectedComponent={selectedComponent}
          currentCode={editorState.code}
          onPropertiesChange={handlePropertiesChange}
          onHookToggle={handleHookToggle}
          onMultipleHookToggle={applyMultipleHookToggles}
          onDeleteComponent={handleDeleteComponent}
        />
      </div>
    )
  }

  const mainContent = (
    <div className="flex-1 flex flex-col min-h-0 h-full">
      {/* Top Header */}
      <div className="bg-white border-b border-gray-200 px-3 py-3">
        <div className="flex items-center justify-between">
          <div className="flex items-center space-x-4">
            <h1 className="text-lg font-semibold text-gray-900">{name}</h1>
            <p className="text-xs text-gray-500">{dependencies.join(', ')}</p>
          </div>

          <div className="flex items-center space-x-3">
            <button
              onClick={() => setShowPanelManager(true)}
              className="flex items-center space-x-2 px-3 py-2 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
              title="Panel Manager"
            >
              <FaThLarge className="w-4 h-4 text-gray-600" />
              <span className="text-sm text-gray-600">Panels</span>
            </button>
          </div>
        </div>
      </div>

      <div className="flex flex-col flex-1 min-h-0 h-full">
        <div className="flex-1 h-full min-h-0">
          <CodeEditor
            code={code}
            onChange={handleCodeChange}
            onApplyCodeChanges={handleApplyCodeChanges}
            onResetCodeChanges={handleResetCodeChanges}
            onDrop={handleDropToCodeEditor}
            onComponentSave={handleSave}
          />
        </div>
      </div>
    </div>
  )

  return (
    <div
      className="flex h-screen bg-gray-50"
      onDragOver={handleAppDragOver}
      onDrop={(e) => {
        e.preventDefault()
        e.stopPropagation()
      }}
    >
      {/* Panel Yöneticisi Modal */}
      {showPanelManager && (
        <PanelManager
          isOpen={showPanelManager}
          onClose={() => setShowPanelManager(false)}
          panelState={panelState}
          onPanelToggle={(panel) => setPanelState((prev) => ({ ...prev, [panel]: !prev[panel] }))}
        />
      )}
      {/* Sol Sidebar ve ana içerik */}
      {panelState.toolbox ? (
        <Splitter direction="horizontal" initialSize={288} minSize={200} maxSize={400}>
          {renderLeftPanel()}
          <div className="flex flex-1">
            {panelState.properties ? (
              <Splitter
                direction="horizontal"
                initialSize={400}
                minSize={300}
                maxSize={window.innerWidth - 288 - 100}
                reverse={true}
              >
                {mainContent}
                {renderRightPanel()}
              </Splitter>
            ) : (
              mainContent
            )}
          </div>
        </Splitter>
      ) : (
        <div className="flex flex-1">
          {panelState.properties ? (
            <Splitter
              direction="horizontal"
              initialSize={400}
              minSize={300}
              maxSize={window.innerWidth - 100}
              reverse={true}
            >
              {mainContent}
              {renderRightPanel()}
            </Splitter>
          ) : (
            mainContent
          )}
        </div>
      )}
    </div>
  )
}

export default CodeLayout
