import React, { useState, useEffect, useRef } from 'react'
import Editor from '@monaco-editor/react'
import { ComponentDefinition } from '../../proxy/developerKit/componentInfo'
import { generateSingleComponentJSX, generateUniqueId } from '@/utils/codeParser'
import { FaCheck, FaCode, FaMousePointer, FaSave, FaCog, FaTimes } from 'react-icons/fa'
import { Button, toast } from '../ui'
import Notification from '../ui/Notification/Notification'

interface ComponentCodeEditorProps {
  code: string
  onChange: (code: string) => void
  onApplyCodeChanges: (code: string) => void
  onResetCodeChanges: () => void
  language?: string
  theme?: 'vs-dark' | 'light'
  onCursorChange?: (componentId: string | null) => void
  onComponentAdded?: (componentDef: ComponentDefinition) => void
  onComponentSave: () => void
}

export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
  code,
  onChange,
  onApplyCodeChanges,
  onResetCodeChanges,
  language = 'typescript',
  theme = 'vs-dark',
  onCursorChange,
  onComponentAdded,
  onComponentSave,
}) => {
  const [localCode, setLocalCode] = useState(code)
  const [hasChanges, setHasChanges] = useState(false)
  const [isFormatting, setIsFormatting] = useState(false)
  const [showSettings, setShowSettings] = useState(false)
  const [editorTheme, setEditorTheme] = useState(theme)
  const [fontSize, setFontSize] = useState(14)
  const [wordWrap, setWordWrap] = useState<'on' | 'off'>('on')
  const [minimap, setMinimap] = useState(true)
  const [showSuccessMessage, setShowSuccessMessage] = useState(false)
  const [isDragOver, setIsDragOver] = useState(false)
  const [dropIndicator, setDropIndicator] = useState<{
    show: boolean
    line: number
    column: number
  }>({ show: false, line: 0, column: 0 })

  const editorRef = useRef<any>(null)
  const containerRef = useRef<HTMLDivElement>(null)
  // Refs to keep latest values accessible inside native DOM listeners
  const localCodeRef = useRef(localCode)
  const dropCallbacksRef = useRef({ onChange, onComponentAdded, onApplyCodeChanges })

  useEffect(() => {
    setLocalCode(code)
    setHasChanges(false)
  }, [code])

  useEffect(() => {
    localCodeRef.current = localCode
  }, [localCode])

  useEffect(() => {
    dropCallbacksRef.current = { onChange, onComponentAdded, onApplyCodeChanges }
  }, [onChange, onComponentAdded, onApplyCodeChanges])

  const findComponentIdAtPosition = (
    code: string,
    position: { lineNumber: number; column: number },
  ): string | null => {
    const lines = code.split('\n')
    const currentLineIndex = position.lineNumber - 1

    // Önce bulunduğu satırı kontrol et
    const line = lines[currentLineIndex] || ''
    const idMatch = line.match(/id=["']([\w-]+)["']/)
    if (idMatch) return idMatch[1]

    // Eğer bulunduğu satırda yoksa, yakındaki satırları kontrol et
    // Önce yukarı doğru ara, sonra aşağı doğru ara
    for (let distance = 1; distance <= 3; distance++) {
      // Yukarı ara
      if (currentLineIndex - distance >= 0) {
        const upLine = lines[currentLineIndex - distance] || ''
        // Component tag başlangıcını kontrol et
        const componentMatch = upLine.match(/<([A-Z][a-zA-Z]*)/)
        if (componentMatch) {
          // Bu component tag'inin ID'sini ara (aynı satırda veya sonraki satırlarda)
          for (
            let j = currentLineIndex - distance;
            j <= Math.min(lines.length - 1, currentLineIndex + 2);
            j++
          ) {
            const searchLine = lines[j] || ''
            const foundId = searchLine.match(/id=["']([\w-]+)["']/)
            if (foundId) return foundId[1]
          }
        }
      }

      // Aşağı ara
      if (currentLineIndex + distance < lines.length) {
        const downLine = lines[currentLineIndex + distance] || ''
        const componentMatch = downLine.match(/<([A-Z][a-zA-Z]*)/)
        if (componentMatch) {
          // Bu component tag'inin ID'sini ara
          for (
            let j = currentLineIndex + distance;
            j <= Math.min(lines.length - 1, currentLineIndex + distance + 2);
            j++
          ) {
            const searchLine = lines[j] || ''
            const foundId = searchLine.match(/id=["']([\w-]+)["']/)
            if (foundId) return foundId[1]
          }
        }
      }
    }

    // Hiçbir şey bulunamadıysa, cursor'ın bulunduğu satırda herhangi bir JSX tag var mı kontrol et
    const jsxMatch = line.match(/<\/?([A-Z][a-zA-Z]*)/)
    if (jsxMatch) {
      // Bu tag'e ait ID'yi bulabilir miyiz?
      const componentName = jsxMatch[1]
      for (
        let i = Math.max(0, currentLineIndex - 5);
        i <= Math.min(lines.length - 1, currentLineIndex + 5);
        i++
      ) {
        const searchLine = lines[i] || ''
        if (searchLine.includes(`<${componentName}`) && searchLine.includes('id=')) {
          const foundId = searchLine.match(/id=["']([\w-]+)["']/)
          if (foundId) return foundId[1]
        }
      }
    }

    return null
  }

  /**
   * Returns true if the given 1-based lineNumber is inside a `return (...)` block.
   * Uses parenthesis depth counting to track entry and exit of the return expression.
   */
  const isPositionInsideJSXReturn = (codeStr: string, lineNumber: number): boolean => {
    const lines = codeStr.split('\n')
    let insideReturn = false
    let parenDepth = 0

    for (let i = 0; i < lineNumber && i < lines.length; i++) {
      const line = lines[i]
      if (!insideReturn) {
        if (/\breturn\s*\(/.test(line)) {
          insideReturn = true
          parenDepth = 0
          const returnIdx = line.search(/\breturn/)
          const fromReturn = line.slice(returnIdx)
          for (const ch of fromReturn) {
            if (ch === '(') parenDepth++
            else if (ch === ')') {
              parenDepth--
              if (parenDepth <= 0) {
                insideReturn = false
                break
              }
            }
          }
        }
      } else {
        for (const ch of line) {
          if (ch === '(') parenDepth++
          else if (ch === ')') {
            parenDepth--
            if (parenDepth <= 0) {
              insideReturn = false
              break
            }
          }
        }
      }
    }
    return insideReturn
  }

  const handleEditorCursorChange = () => {
    if (!editorRef.current) return
    const position = editorRef.current.getPosition()
    if (!position) return

    const id = findComponentIdAtPosition(localCode, position)
    if (onCursorChange) onCursorChange(id)
  }

  const handleEditorDidMount = (editor: any, monaco: any) => {
    editorRef.current = editor

    monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
      target: monaco.languages.typescript.ScriptTarget.Latest,
      allowNonTsExtensions: true,
      moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
      module: monaco.languages.typescript.ModuleKind.CommonJS,
      noEmit: true,
      esModuleInterop: true,
      jsx: monaco.languages.typescript.JsxEmit.React,
      reactNamespace: 'React',
      allowJs: true,
      typeRoots: ['node_modules/@types'],
    })

    editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
      handleApplyChanges()
    })

    editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyF, () => {
      handleFormatCode()
    })

    editor.onDidChangeCursorPosition(handleEditorCursorChange)

    // Intercept Monaco's native drop so it never inserts raw JSON text.
    // We handle the drop ourselves: insert JSX when inside return(), skip otherwise.
    const domNode = editor.getDomNode()
    if (domNode) {
      domNode.addEventListener(
        'drop',
        (nativeEvent: DragEvent) => {
          nativeEvent.preventDefault()
          nativeEvent.stopPropagation()
          nativeEvent.stopImmediatePropagation()

          if (!nativeEvent.dataTransfer) return

          // Read component definition from drag data
          let componentDefData: string | undefined
          for (const fmt of ['application/json', 'text/plain']) {
            const d = nativeEvent.dataTransfer.getData(fmt)
            if (d) {
              componentDefData = d
              break
            }
          }
          if (!componentDefData) return

          let componentDef: any
          try {
            componentDef = JSON.parse(componentDefData)
          } catch {
            return
          }
          if (!componentDef?.name) return

          // Resolve the drop position inside Monaco
          const dropPos = editor.getTargetAtClientPoint(nativeEvent.clientX, nativeEvent.clientY)
          const position = dropPos?.position ?? editor.getPosition()
          if (!position) return

          // Only allow drop inside JSX return(...) block
          if (!isPositionInsideJSXReturn(localCodeRef.current, position.lineNumber)) {
            toast.push(
              <Notification type="warning" duration={3000}>
                Bileşen yalnızca <strong>return(...)</strong> bloğu içine eklenebilir.
              </Notification>,
              { placement: 'bottom-end' },
            )
            return
          }

          const componentId = generateUniqueId()
          const adaptedProps = {
            ...(componentDef.properties || []).reduce(
              (acc: any, prop: any) => {
                acc[prop.name] = {
                  type: prop.type,
                  value: prop.value,
                  ...(prop.options ? { options: prop.options } : {}),
                }
                return acc
              },
              {} as Record<string, any>,
            ),
            id: { type: 'string', value: componentId },
          }

          const componentJSX = generateSingleComponentJSX(componentDef.name, adaptedProps)
          const componentDefWithId = {
            ...componentDef,
            id: componentId,
            properties: [
              ...(componentDef.properties || []).filter((p: any) => p.name !== 'id'),
              { name: 'id', type: 'string', value: componentId, category: 'properties' },
            ],
          }

          const lines = localCodeRef.current.split('\n')
          const indent = (lines[position.lineNumber - 1] || '').match(/^(\s*)/)?.[1] ?? '      '
          const formattedJSX = `${indent}${componentJSX}`
          const newLines = [...lines]
          newLines.splice(position.lineNumber, 0, formattedJSX)
          const newCode = newLines.join('\n')

          setLocalCode(newCode)
          const {
            onChange: onChg,
            onComponentAdded: onAdded,
            onApplyCodeChanges: onApply,
          } = dropCallbacksRef.current
          onChg(newCode)
          if (onAdded) onAdded(componentDefWithId)
          setTimeout(() => onApply(newCode), 100)

          setIsDragOver(false)
          setDropIndicator({ show: false, line: 0, column: 0 })
        },
        true, // capture phase — fires before Monaco's own listeners
      )
    }
  }

  const handleCodeChange = (value: string | undefined) => {
    if (value !== undefined) {
      setLocalCode(value)
      setHasChanges(value !== code)
      onChange(value)
    }
  }

  const handleApplyChanges = () => {
    onApplyCodeChanges(localCode)
    setHasChanges(false)
    setShowSuccessMessage(true)
    handleFormatCode()
    setTimeout(() => setShowSuccessMessage(false), 3000)
  }

  const handleFormatCode = async () => {
    if (editorRef.current) {
      setIsFormatting(true)
      try {
        await editorRef.current.getAction('editor.action.formatDocument').run()
      } catch (error) {
        console.error('Kod formatlama hatası:', error)
      } finally {
        setIsFormatting(false)
      }
    }
  }

  const handleResetChanges = () => {
    setLocalCode(code)
    setHasChanges(false)
    onResetCodeChanges()
  }

  // Drag & Drop handlers for Code Editor
  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()

    if (!editorRef.current || !containerRef.current) return

    try {
      const hasComponentData = e.dataTransfer.types.some(
        (type) => type === 'application/json' || type === 'text/plain' || type === 'text',
      )

      if (hasComponentData) {
        e.dataTransfer.dropEffect = 'copy'
        setIsDragOver(true)

        // Get cursor position from mouse coordinates
        const rect = containerRef.current.getBoundingClientRect()
        const x = e.clientX - rect.left
        const y = e.clientY - rect.top

        // Convert to editor position
        const position = editorRef.current.getTargetAtClientPoint(x, y)
        if (position) {
          setDropIndicator({
            show: true,
            line: position.position.lineNumber,
            column: position.position.column,
          })
        }
      }
    } catch (err) {
      console.warn('Error handling drag over:', err)
    }
  }

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()

    if (!containerRef.current) return

    const rect = containerRef.current.getBoundingClientRect()
    const x = e.clientX
    const y = e.clientY

    if (x <= rect.left || x >= rect.right || y <= rect.top || y >= rect.bottom) {
      setIsDragOver(false)
      setDropIndicator({ show: false, line: 0, column: 0 })
    }
  }

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()

    setIsDragOver(false)
    setDropIndicator({ show: false, line: 0, column: 0 })

    if (!editorRef.current || !containerRef.current) return

    try {
      let componentDefData
      const formats = ['application/json', 'text/plain', 'text']

      // Sürüklenen bileşenin verisini al
      for (const format of formats) {
        const data = e.dataTransfer.getData(format)

        if (data) {
          componentDefData = data
          break
        }
      }

      if (!componentDefData) return

      let componentDef
      try {
        componentDef = JSON.parse(componentDefData)
      } catch (error) {
        console.error('Component verisi çözümlenemedi:', error)
        return
      }

      // 1. Component ID'sini oluştur
      const componentId = generateUniqueId()

      // 2. Props'ları adapt et ve ID'yi dahil et
      const adaptedProps = {
        ...(componentDef.properties || []).reduce(
          (acc: any, prop: any) => {
            acc[prop.name] = {
              type: prop.type,
              value: prop.value,
              ...(prop.options ? { options: prop.options } : {}),
            }
            return acc
          },
          {} as Record<string, any>,
        ),
        id: {
          type: 'string',
          value: componentId,
        },
      }

      // 3. JSX oluştur
      const componentJSX = generateSingleComponentJSX(componentDef.name, adaptedProps)

      // 4. Component tanımını ID ile genişlet
      const componentDefWithId = {
        ...componentDef,
        id: componentId,
        properties: [
          ...(componentDef.properties || []).filter((p: any) => p.name !== 'id'),
          {
            name: 'id',
            type: 'string',
            value: componentId,
            category: 'properties',
          },
        ],
      }

      // 5. Pozisyonu al
      let position = editorRef.current.getPosition()
      if (!position) {
        console.error('Geçersiz pozisyon tespit edildi. Yedek pozisyon kullanılıyor.')
        position = { lineNumber: 0, column: 0 }
      }

      // 6. JSX kodunu pozisyonda ekle
      const newCode = insertJSXAtPosition(localCode, componentJSX, position)
      setLocalCode(newCode)
      onChange(newCode)

      // 7. Parent'a bildirim gönder
      if (onComponentAdded) {
        onComponentAdded(componentDefWithId)
      }

      // 8. Uygulamayı tetikle
      setTimeout(() => {
        onApplyCodeChanges(newCode)
      }, 100)
    } catch (error) {
      console.error('Bileşen bırakılırken hata oluştu:', error)
    }
  }

  const insertJSXAtPosition = (
    code: string,
    jsx: string,
    position: { lineNumber: number; column: number },
  ): string => {
    const updatedCode = code
    const lines = updatedCode.split('\n')

    // Pozisyonu doğrula (import eklendiyse satır numaraları değişmiş olabilir)
    if (position.lineNumber < 1 || position.lineNumber > lines.length) {
      console.error('Geçersiz satır numarası:', position.lineNumber)
      position.lineNumber = lines.length // Geçersiz satırda son satıra ekle
    }

    const line = lines[position.lineNumber - 1] // 1 tabanlı indeks, 0 tabanlıya çevrilir

    if (!line) {
      console.error('Satır bulunamadı:', position.lineNumber)
      return updatedCode // Eğer satır yoksa, kodu değiştirmeden döndür
    }

    // Satırın indentasyonunu belirle
    const indentMatch = line.match(/^(\s*)/)
    const indent = indentMatch ? indentMatch[1] : '      ' // Default 6 boşluk

    // Component'i yeni satıra ekle (mevcut satırın altına)
    const formattedJSX = `${indent}${jsx}`
    lines.splice(position.lineNumber, 0, formattedJSX)

    return lines.join('\n') // Tüm satırları birleştir ve yeni kodu döndür
  }

  const handleDragEnter = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
  }

  return (
    <div
      ref={containerRef}
      className={`w-full h-full flex flex-col min-h-0 max-h-full bg-gray-900 text-white relative ${
        isDragOver ? 'ring-2 ring-blue-500 ring-offset-2' : ''
      }`}
      style={{ flex: 1, minHeight: 0, maxHeight: '100vh' }}
      onDragOver={handleDragOver}
      onDragEnter={handleDragEnter}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
    >
      {/* Drop Indicator */}
      {dropIndicator.show && (
        <div className="absolute inset-0 bg-blue-500 bg-opacity-10 border-2 border-dashed border-blue-500 rounded-lg flex items-center justify-center z-50 pointer-events-none">
          <div className="bg-blue-500 text-white px-4 py-2 rounded-lg font-medium shadow-lg">
            Bileşeni Line {dropIndicator.line}, Column {dropIndicator.column} konumuna bırak
          </div>
        </div>
      )}

      {/* Header */}
      <div className="bg-gray-800 border-b border-gray-700 p-4 flex items-end justify-between shrink-0">
        <div className="flex items-center gap-2">
          <Button
            loading={isFormatting}
            icon={<FaCode className="w-4 h-4" />}
            variant="default"
            size="sm"
            onClick={handleFormatCode}
          >
            Formatla
          </Button>

          <Button
            icon={<FaCog className="w-4 h-4" />}
            variant={showSettings ? 'solid' : 'default'}
            color="blue-600"
            size="sm"
            onClick={() => setShowSettings(!showSettings)}
          >
            Ayarlar
          </Button>

          <Button
            icon={<FaTimes className="w-4 h-4" />}
            variant="solid"
            color="red-600"
            size="sm"
            onClick={handleResetChanges}
          >
            Sıfırla
          </Button>

          <Button
            icon={<FaCheck className="w-4 h-4" />}
            variant="solid"
            color="green-600"
            size="sm"
            onClick={handleApplyChanges}
          >
            Uygula
          </Button>
        </div>
        <div className="col-span-2 flex items-center justify-end">
          <Button
            icon={<FaSave className="w-4 h-4" />}
            variant="solid"
            color="yellow-600"
            size="sm"
            className="shadow-sm"
            onClick={onComponentSave}
          >
            Kaydet
          </Button>
        </div>
      </div>

      {/* Settings Panel */}
      {showSettings && (
        <div className="bg-gray-800 border-b border-gray-700 p-4 shrink-0">
          <div className="grid grid-cols-4 gap-4">
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">Tema</label>
              <select
                value={editorTheme}
                className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                onChange={(e) => setEditorTheme(e.target.value as 'vs-dark' | 'light')}
              >
                <option value="vs-dark">Koyu</option>
                <option value="light">Açık</option>
              </select>
            </div>

            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">Font Boyutu</label>
              <input
                type="number"
                min="10"
                max="24"
                value={fontSize}
                className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                onChange={(e) => setFontSize(parseInt(e.target.value))}
              />
            </div>

            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">
                Kelime Kaydırma
              </label>
              <select
                value={wordWrap}
                className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
                onChange={(e) => setWordWrap(e.target.value as 'on' | 'off')}
              >
                <option value="on">Açık</option>
                <option value="off">Kapalı</option>
              </select>
            </div>

            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">Mini Harita</label>
              <Button
                block
                variant={minimap ? 'solid' : 'default'}
                color="blue-600"
                size="sm"
                onClick={() => setMinimap(!minimap)}
              >
                {minimap ? 'Etkin' : 'Devre Dışı'}
              </Button>
            </div>
          </div>
        </div>
      )}

      {/* Editor */}
      <div className="flex-1 h-full">
        <Editor
          height="100%"
          width="100%"
          language={language}
          theme={editorTheme}
          value={localCode}
          options={{
            fontSize: fontSize,
            wordWrap: wordWrap,
            minimap: { enabled: minimap },
            automaticLayout: true,
            scrollBeyondLastLine: false,
            renderWhitespace: 'selection',
            bracketPairColorization: { enabled: true },
            guides: {
              bracketPairs: true,
              indentation: true,
            },
            suggest: {
              showKeywords: true,
              showSnippets: true,
              showFunctions: true,
              showConstructors: true,
              showFields: true,
              showVariables: true,
              showClasses: true,
              showStructs: true,
              showInterfaces: true,
              showModules: true,
              showProperties: true,
              showEvents: true,
              showOperators: true,
              showUnits: true,
              showValues: true,
              showConstants: true,
              showEnums: true,
              showEnumMembers: true,
              showColors: true,
              showFiles: true,
              showReferences: true,
              showFolders: true,
              showTypeParameters: true,
              showUsers: true,
              showIssues: true,
            },
            quickSuggestions: {
              other: true,
              comments: true,
              strings: true,
            },
            parameterHints: {
              enabled: true,
            },
            hover: {
              enabled: true,
            },
            contextmenu: true,
            mouseWheelZoom: true,
            cursorBlinking: 'smooth',
            cursorSmoothCaretAnimation: 'on',
            smoothScrolling: true,
            folding: true,
            foldingStrategy: 'indentation',
            showFoldingControls: 'always',
            unfoldOnClickAfterEndOfLine: false,
            tabSize: 2,
            insertSpaces: true,
            detectIndentation: true,
            trimAutoWhitespace: true,
            formatOnPaste: true,
            formatOnType: true,
          }}
          onChange={handleCodeChange}
          onMount={handleEditorDidMount}
        />
      </div>

      {/* Status Bar */}
      <div className="bg-gray-800 border-t border-gray-700 px-4 py-2 flex items-center justify-between text-sm text-gray-400 shrink-0">
        <div className="flex items-center gap-4">
          <span>TypeScript React</span>
          <span>UTF-8</span>
          <span>LF</span>
        </div>
        <div className="flex items-center gap-4">
          <span>Satır 1, Sütun 1</span>
          <span>Boşluklar: 2</span>
          {hasChanges && <span className="text-orange-400">● Kaydedilmemiş değişiklikler</span>}
          {showSuccessMessage && (
            <span className="text-green-400 flex items-center gap-1">
              <FaCheck className="w-4 h-4" />
            </span>
          )}
          {isDragOver && (
            <span className="text-blue-400 flex items-center gap-1">
              <FaMousePointer className="w-4 h-4" />
              Bileşeni bırakmaya hazır
            </span>
          )}
        </div>
      </div>
    </div>
  )
}
