// Gestión de templates persistentes
import { readFile, writeFile, mkdir } from 'fs/promises'
import { existsSync } from 'fs'
import { join } from 'path'

export interface Operation {
  op: string
  [key: string]: any
}

export interface TemplateVariable {
  name: string
  label?: string
  defaultValue?: string
}

export interface PrintTemplate {
  id: string
  name: string
  description?: string
  operations: Operation[]
  variables: TemplateVariable[]
  createdAt: string
  updatedAt: string
}

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

// Extraer variables de las operaciones
export function extractVariables(operations: Operation[]): TemplateVariable[] {
  const variablesMap = new Map<string, TemplateVariable>()

  for (const op of operations) {
    // Buscar en campos que pueden contener variables
    const searchFields = ['value', 'data']
    for (const field of searchFields) {
      if (typeof op[field] === 'string') {
        const matches = op[field].matchAll(VARIABLE_REGEX)
        for (const match of matches) {
          const [, name, label, defaultValue] = match
          // Solo guardar la primera definición de cada variable
          if (!variablesMap.has(name)) {
            variablesMap.set(name, {
              name,
              label: label || undefined,
              defaultValue: defaultValue || undefined
            })
          }
        }
      }
    }
  }

  return Array.from(variablesMap.values())
}

// Resolver variables en operaciones reemplazando {{nombre}} con valores
export function resolveVariables(
  operations: Operation[],
  values: Record<string, string> = {}
): Operation[] {
  return JSON.parse(JSON.stringify(operations)).map((op: Operation) => {
    for (const [key, val] of Object.entries(op)) {
      if (typeof val === 'string') {
        op[key] = val.replace(VARIABLE_REGEX, (_, name) => values[name] ?? '')
      }
    }
    return op
  })
}

export interface TemplatesStore {
  templates: PrintTemplate[]
}

// Directorio de datos persistentes
const DATA_DIR = join(process.cwd(), 'data')
const TEMPLATES_FILE = join(DATA_DIR, 'templates.json')

// Asegurar que el directorio existe
async function ensureDataDir(): Promise<void> {
  if (!existsSync(DATA_DIR)) {
    await mkdir(DATA_DIR, { recursive: true })
  }
}

// Leer store de templates
export async function readTemplatesStore(): Promise<TemplatesStore> {
  await ensureDataDir()

  try {
    const data = await readFile(TEMPLATES_FILE, 'utf-8')
    return JSON.parse(data)
  } catch {
    // Si no existe el archivo, retornar store vacío
    return {
      templates: []
    }
  }
}

// Guardar store de templates
export async function writeTemplatesStore(store: TemplatesStore): Promise<void> {
  await ensureDataDir()
  await writeFile(TEMPLATES_FILE, JSON.stringify(store, null, 2), 'utf-8')
}

// Generar ID único
function generateId(): string {
  return `template_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
}

// CRUD Operations

export async function getAllTemplates(): Promise<PrintTemplate[]> {
  const store = await readTemplatesStore()
  return store.templates
}

export async function getTemplateById(id: string): Promise<PrintTemplate | null> {
  const store = await readTemplatesStore()
  return store.templates.find(t => t.id === id) || null
}

export async function createTemplate(data: {
  name: string
  description?: string
  operations: Operation[]
}): Promise<PrintTemplate> {
  const store = await readTemplatesStore()

  const now = new Date().toISOString()
  const template: PrintTemplate = {
    id: generateId(),
    name: data.name,
    description: data.description || '',
    operations: data.operations,
    variables: extractVariables(data.operations),
    createdAt: now,
    updatedAt: now
  }

  store.templates.push(template)
  await writeTemplatesStore(store)
  return template
}

export async function updateTemplate(id: string, data: Partial<{
  name: string
  description: string
  operations: Operation[]
}>): Promise<PrintTemplate | null> {
  const store = await readTemplatesStore()
  const index = store.templates.findIndex(t => t.id === id)

  if (index === -1) return null

  // Si se actualizan las operaciones, recalcular las variables
  const variables = data.operations
    ? extractVariables(data.operations)
    : store.templates[index].variables

  store.templates[index] = {
    ...store.templates[index],
    ...data,
    variables,
    updatedAt: new Date().toISOString()
  }

  await writeTemplatesStore(store)
  return store.templates[index]
}

export async function deleteTemplate(id: string): Promise<boolean> {
  const store = await readTemplatesStore()
  const index = store.templates.findIndex(t => t.id === id)

  if (index === -1) return false

  store.templates.splice(index, 1)
  await writeTemplatesStore(store)
  return true
}

export async function duplicateTemplate(id: string): Promise<PrintTemplate | null> {
  const template = await getTemplateById(id)
  if (!template) return null

  return createTemplate({
    name: `${template.name} (copia)`,
    description: template.description,
    operations: JSON.parse(JSON.stringify(template.operations))
  })
}
