import type { Operation } from './usePrintQueue'

// Configuración de caracteres por línea según fuente y ancho
export const CHAR_LIMITS = {
  font_a: { normal: 33, doubleWidth: 16 },
  font_b: { normal: 40, doubleWidth: 20 }
} as const

export type FontType = 'font_a' | 'font_b'
export type AlignType = 'left' | 'center' | 'right'

// Segmento de texto: puede ser texto normal o una variable
export interface TextSegment {
  type: 'text' | 'variable'
  content: string
  variableName?: string // Solo para type='variable'
}

// Una línea en el preview
export interface PreviewLine {
  segments: TextSegment[]
  fullText: string // Texto completo para calcular longitud
  align: AlignType
  bold: boolean
  underline: boolean
  doubleWidth: boolean
  doubleHeight: boolean
  font: FontType
  charLimit: number
  exceedsLimit: boolean
  isFeed: boolean // true si es una línea vacía (feed)
}

// Estado del preview
export interface PreviewState {
  lines: PreviewLine[]
  font: FontType
  warnings: string[]
  totalLines: number
}

// Regex para detectar variables: {{nombre}} o {{nombre:label:default}}
const VARIABLE_REGEX = /\{\{(\w+)(?::([^:}]+))?(?::([^}]+))?\}\}/g

// Parsear texto para extraer segmentos (texto normal y variables)
export function parseTextSegments(text: string): TextSegment[] {
  const segments: TextSegment[] = []
  let lastIndex = 0
  let match: RegExpExecArray | null

  // Reset regex
  VARIABLE_REGEX.lastIndex = 0

  while ((match = VARIABLE_REGEX.exec(text)) !== null) {
    // Agregar texto antes de la variable
    if (match.index > lastIndex) {
      segments.push({
        type: 'text',
        content: text.slice(lastIndex, match.index)
      })
    }

    // Agregar la variable
    const [fullMatch, name, _label, defaultValue] = match
    segments.push({
      type: 'variable',
      content: defaultValue || name, // Mostrar default o nombre
      variableName: name
    })

    lastIndex = match.index + fullMatch.length
  }

  // Agregar texto restante
  if (lastIndex < text.length) {
    segments.push({
      type: 'text',
      content: text.slice(lastIndex)
    })
  }

  // Si no hay segmentos, el texto completo es normal
  if (segments.length === 0 && text) {
    segments.push({ type: 'text', content: text })
  }

  return segments
}

// Obtener el texto completo de los segmentos
export function getFullText(segments: TextSegment[]): string {
  return segments.map(s => s.content).join('')
}

// Calcular límite de caracteres
export function getCharLimit(font: FontType, doubleWidth: boolean): number {
  const limits = CHAR_LIMITS[font]
  return doubleWidth ? limits.doubleWidth : limits.normal
}

// Procesar operaciones en líneas de preview
export function processOperations(
  operations: Operation[],
  variableValues: Record<string, string> = {}
): PreviewState {
  const lines: PreviewLine[] = []
  const warnings: string[] = []

  // Estado actual (se modifica con cada operación de estilo)
  let currentState = {
    font: 'font_a' as FontType,
    align: 'left' as AlignType,
    bold: false,
    underline: false,
    doubleWidth: false,
    doubleHeight: false
  }

  for (const op of operations) {
    switch (op.op) {
      case 'text': {
        let text = op.value || ''

        // Reemplazar variables con valores proporcionados
        const segments = parseTextSegments(text)
        const resolvedSegments = segments.map(seg => {
          if (seg.type === 'variable' && seg.variableName && variableValues[seg.variableName]) {
            return {
              ...seg,
              content: variableValues[seg.variableName]
            }
          }
          return seg
        })

        const fullText = getFullText(resolvedSegments)
        const charLimit = getCharLimit(currentState.font, currentState.doubleWidth)
        const exceedsLimit = fullText.length > charLimit

        if (exceedsLimit) {
          warnings.push(`Línea excede ${charLimit} chars: "${fullText.slice(0, 20)}..."`)
        }

        lines.push({
          segments: resolvedSegments,
          fullText,
          ...currentState,
          charLimit,
          exceedsLimit,
          isFeed: false
        })
        break
      }

      case 'textAlign':
        currentState.align = (op.align as AlignType) || 'left'
        break

      case 'textFont':
        if (op.font === 'font_a' || op.font === 'font_b') {
          currentState.font = op.font
        }
        break

      case 'textSize':
        currentState.doubleWidth = (op.width || 1) >= 2
        currentState.doubleHeight = (op.height || 1) >= 2
        break

      case 'textDouble':
        currentState.doubleWidth = op.dw === true
        currentState.doubleHeight = op.dh === true
        break

      case 'textStyle':
        if (op.em !== undefined) currentState.bold = op.em
        if (op.ul !== undefined) currentState.underline = op.ul
        break

      case 'feed':
      case 'feedLine': {
        const lineCount = op.line || op.lines || 1
        for (let i = 0; i < lineCount; i++) {
          lines.push({
            segments: [],
            fullText: '',
            ...currentState,
            charLimit: getCharLimit(currentState.font, currentState.doubleWidth),
            exceedsLimit: false,
            isFeed: true
          })
        }
        break
      }

      case 'cut':
        // El corte no agrega líneas visuales, solo indica fin
        break

      // Ignorar operaciones que no afectan el preview visual
      case 'pulse':
      case 'textRotate':
      case 'textLineSpace':
      case 'feedUnit':
        break
    }
  }

  return {
    lines,
    font: currentState.font,
    warnings,
    totalLines: lines.length
  }
}

// Composable para el preview
export function usePreview() {
  const previewState = ref<PreviewState | null>(null)
  const variableValues = ref<Record<string, string>>({})

  // Procesar operaciones y generar preview
  function generatePreview(operations: Operation[], initialValues: Record<string, string> = {}) {
    variableValues.value = { ...initialValues }
    previewState.value = processOperations(operations, variableValues.value)
  }

  // Actualizar valor de una variable
  function updateVariable(name: string, value: string, operations: Operation[]) {
    variableValues.value[name] = value
    previewState.value = processOperations(operations, variableValues.value)
  }

  // Obtener todas las variables únicas de las operaciones
  function extractVariables(operations: Operation[]): Array<{ name: string; defaultValue: string }> {
    const variables = new Map<string, string>()

    for (const op of operations) {
      if (op.op === 'text' && op.value) {
        let match: RegExpExecArray | null
        VARIABLE_REGEX.lastIndex = 0

        while ((match = VARIABLE_REGEX.exec(op.value)) !== null) {
          const [, name, , defaultValue] = match
          if (!variables.has(name)) {
            variables.set(name, defaultValue || '')
          }
        }
      }
    }

    return Array.from(variables.entries()).map(([name, defaultValue]) => ({
      name,
      defaultValue
    }))
  }

  return {
    previewState: readonly(previewState),
    variableValues: readonly(variableValues),
    generatePreview,
    updateVariable,
    extractVariables,
    CHAR_LIMITS
  }
}
