import type { ToolConfig } from './index'
import { useCanvasStore } from '../../../stores/canvas'
import {
  renderInlineComponent,
  componentsApi,
  type VueComponentDefinition
} from '../../dynamicComponents'
import { getWindowDefinitions } from './canvasHandlers'

function getCanvasContainer() {
  return document.getElementById('canvas-content')
}

function removePlaceholder(container: HTMLElement) {
  const placeholder = container.querySelector('.canvas-placeholder')
  if (placeholder) {
    placeholder.remove()
    window.dispatchEvent(new CustomEvent('canvas-content-rendered'))
  }
}

// Track which component fields have been read (for edit validation)
const readComponents = new Set<string>() // format: "component_id:field"

export function createComponentHandlers(): ToolConfig[] {
  return [
    {
      name: 'save_vue_component',
      description: 'Guarda un componente Vue en la base de datos',
      category: 'component',
      schema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'ID unico del componente' },
          name: { type: 'string', description: 'Nombre del componente' },
          template: { type: 'string', description: 'Template HTML' },
          setup: { type: 'string', description: 'Codigo de setup' },
          style: { type: 'string', description: 'CSS' },
          props: { type: 'array', items: { type: 'string' }, description: 'Props' },
          imports: { type: 'array', items: { type: 'string' }, description: 'Imports de Vue' },
          tags: { type: 'array', items: { type: 'string' }, description: 'Etiquetas para categorizar el componente' }
        },
        required: ['name', 'template']
      },
      handler: async (args: Omit<VueComponentDefinition, 'id'> & { id?: string; tags?: string[] }) => {
        try {
          const result = await componentsApi.save({
            id: args.id || `comp-${Date.now()}`,
            name: args.name,
            template: args.template,
            setup: args.setup,
            style: args.style,
            props: args.props,
            imports: args.imports,
            tags: args.tags
          })
          const canvasStore = useCanvasStore()
          canvasStore.addToHistory({ tool: 'save_vue_component', args, timestamp: Date.now() })
          return `Componente "${args.name}" guardado con ID: ${result.id}`
        } catch (e: any) {
          return `Error al guardar: ${e.message}`
        }
      }
    },
    {
      name: 'load_vue_component',
      description: 'Carga un componente guardado y lo renderiza',
      category: 'component',
      schema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'ID del componente' },
          componentProps: { type: 'object', description: 'Props para el componente' },
          mode: { type: 'string', enum: ['replace', 'append'], description: 'Modo' },
          x: { type: 'number', description: 'Posicion X inicial' },
          y: { type: 'number', description: 'Posicion Y inicial' },
          width: { type: 'number', description: 'Ancho inicial' },
          height: { type: 'number', description: 'Alto inicial' }
        },
        required: ['id']
      },
      handler: async (args: { id: string; componentProps?: Record<string, any>; mode?: string; x?: number; y?: number; width?: number; height?: number }) => {
        try {
          const definition = await componentsApi.getById(args.id)
          if (!definition) {
            return `Error: Componente "${args.id}" no encontrado`
          }

          const container = getCanvasContainer()
          if (!container) return 'Error: canvas no encontrado'

          removePlaceholder(container)

          const isAppend = args.mode === 'append'
          const layout = { x: args.x, y: args.y, width: args.width, height: args.height }
          const result = renderInlineComponent(definition, container, args.componentProps || {}, isAppend, layout)

          // Track definition for snapshot capture
          getWindowDefinitions().set(definition.id, {
            source: 'db',
            componentId: args.id,
            definition,
            componentProps: args.componentProps || {}
          })

          ;(window as any).__vueComponentUnmount = result.unmount

          const canvasStore = useCanvasStore()
          canvasStore.addToHistory({ tool: 'load_vue_component', args, timestamp: Date.now() })
          return `Componente "${definition.name}" cargado y renderizado`
        } catch (e: any) {
          return `Error: ${e.message}`
        }
      }
    },
    {
      name: 'list_vue_components',
      description: 'Lista todos los componentes guardados (activos)',
      category: 'component',
      schema: {
        type: 'object',
        properties: {
          include_archived: { type: 'boolean', description: 'Incluir componentes archivados' }
        }
      },
      handler: async (args: { include_archived?: boolean }) => {
        try {
          const components = await componentsApi.getAll({ includeArchived: args.include_archived })
          if (components.length === 0) {
            return 'No hay componentes guardados'
          }
          const list = components.map(c => {
            const tags = c.tags?.length ? ` [${c.tags.join(', ')}]` : ''
            const status = c.status === 'archived' ? ' (archivado)' : ''
            return `- ${c.id}: ${c.name}${tags}${status}`
          }).join('\n')
          return `Componentes guardados (${components.length}):\n${list}`
        } catch (e: any) {
          return `Error: ${e.message}`
        }
      }
    },
    {
      name: 'delete_vue_component',
      description: 'Archiva un componente (soft delete). El componente no se elimina, solo se oculta.',
      category: 'component',
      schema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'ID del componente' }
        },
        required: ['id']
      },
      handler: async (args: { id: string }) => {
        try {
          const result = await componentsApi.delete(args.id)
          const warning = result.warning ? ` (Nota: ${result.warning})` : ''
          return `Componente "${args.id}" archivado${warning}`
        } catch (e: any) {
          return `Error: ${e.message}`
        }
      }
    },
    {
      name: 'read_component',
      description: 'Lee campos especificos de un componente guardado',
      category: 'component',
      schema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'ID del componente' },
          fields: {
            type: 'array',
            items: { type: 'string', enum: ['template', 'setup', 'style', 'props', 'imports'] },
            description: 'Campos a leer (default: template, setup, style)'
          },
          offset: { type: 'number', description: 'Linea inicial (1-based)' },
          limit: { type: 'number', description: 'Numero de lineas a leer' }
        },
        required: ['id']
      },
      handler: async (args: { id: string; fields?: string[]; offset?: number; limit?: number }) => {
        try {
          const definition = await componentsApi.getById(args.id)
          if (!definition) return `Error: "${args.id}" not found`

          const fields = args.fields || ['template', 'setup', 'style']
          const validFields = ['template', 'setup', 'style', 'props', 'imports'] as const
          const output: string[] = []

          for (const field of fields) {
            if (!validFields.includes(field as any)) continue
            const value = definition[field as keyof typeof definition]
            readComponents.add(`${args.id}:${field}`)

            if (field === 'props' || field === 'imports') {
              const arr = value as string[] | undefined
              output.push(`--- ${field} ---\n${arr?.length ? JSON.stringify(arr) : '(empty)'}`)
            } else {
              const str = (value as string) || ''
              const lines = str.split('\n')
              const total = lines.length
              const start = Math.max(0, (args.offset || 1) - 1)
              const end = args.limit ? start + args.limit : total
              const sliced = lines.slice(start, end)
              const numbered = sliced.map((l, i) => `${String(start + i + 1).padStart(4)}\t${l}`).join('\n')
              const rangeInfo = (args.offset || args.limit) ? ` lines ${start + 1}-${Math.min(end, total)}/${total}` : ` ${total} lines`
              output.push(`--- ${field}${rangeInfo} ---\n${numbered || '(empty)'}`)
            }
          }

          return output.join('\n\n')
        } catch (e: any) {
          return `Error: ${e.message}`
        }
      }
    },
    {
      name: 'edit_component',
      description: 'Edita un campo de componente con reemplazo de strings (requiere read_component previo)',
      category: 'component',
      schema: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'ID del componente' },
          field: { type: 'string', enum: ['template', 'setup', 'style'], description: 'Campo a editar' },
          old_string: { type: 'string', description: 'Texto a reemplazar (debe ser unico en el campo)' },
          new_string: { type: 'string', description: 'Texto de reemplazo' },
          replace_all: { type: 'boolean', description: 'Reemplazar todas las ocurrencias (default: false)' }
        },
        required: ['id', 'field', 'old_string', 'new_string']
      },
      handler: async (args: { id: string; field: string; old_string: string; new_string: string; replace_all?: boolean }) => {
        try {
          if (!readComponents.has(`${args.id}:${args.field}`)) {
            return `Error: read_component "${args.id}" "${args.field}" first`
          }

          const definition = await componentsApi.getById(args.id)
          if (!definition) return `Error: "${args.id}" not found`

          const currentValue = (definition[args.field as keyof typeof definition] as string) || ''

          let count = 0
          let pos = 0
          while ((pos = currentValue.indexOf(args.old_string, pos)) !== -1) {
            count++
            pos += args.old_string.length
          }

          if (count === 0) return `Error: old_string not found in ${args.field}`
          if (count > 1 && !args.replace_all) {
            return `Error: ${count} matches found. Use replace_all:true or add context.`
          }

          const newValue = args.replace_all
            ? currentValue.replaceAll(args.old_string, args.new_string)
            : currentValue.replace(args.old_string, args.new_string)
          await componentsApi.update(args.id, { [args.field]: newValue })

          readComponents.add(`${args.id}:${args.field}`)

          return count > 1
            ? `OK ${args.field} ${currentValue.length}→${newValue.length} (${count} replaced)`
            : `OK ${args.field} ${currentValue.length}→${newValue.length}`
        } catch (e: any) {
          return `Error: ${e.message}`
        }
      }
    }
  ]
}
