/**
 * Composable para manejar la lógica de negocio de catación
 */

import type { SesionCatacion, Muestra, IntensidadValor } from '~/types/catacion'
import { crearSesionVacia, calcularPuntajeFinal } from '~/types/catacion'

export type TabCatacion = 'organoleptica' | 'descriptiva-afectiva' | 'defectos' | 'impresion-global'

// Subcategorías para Organoléptica
export type SubcategoriaOrganoleptica = 'fragancia-aroma' | 'sabor' | 'sensacion-boca' | 'gustos-predominantes'

// Subcategorías para Descriptiva/Afectiva
export type SubcategoriaDescriptivaAfectiva = 'descriptiva' | 'afectiva' | 'fragancia' | 'aroma' | 'sabor' | 'sabor-residual' | 'acidez' | 'dulzor' | 'sensacion-boca' | 'impresion-global'

// Tipo unión de todas las subcategorías
export type Subcategoria = SubcategoriaOrganoleptica | SubcategoriaDescriptivaAfectiva | null

// Tipo para las subcategorías por tab
export type SubcategoriasPorTab = {
  'organoleptica': Subcategoria[]
  'descriptiva-afectiva': Subcategoria[]
  'defectos': Subcategoria[]
  'impresion-global': Subcategoria[]
}

// Clave para localStorage
const STORAGE_KEY_SUBCATEGORIAS = 'riocata-subcategorias-activas'

export const useCatacion = () => {
  const { sesionActiva, cargando, error, guardar, actualizar, eliminar } = useIndexedDB()

  // Cargar subcategorías desde localStorage
  const cargarSubcategoriasDesdeStorage = (): SubcategoriasPorTab => {
    if (import.meta.client) {
      try {
        const stored = localStorage.getItem(STORAGE_KEY_SUBCATEGORIAS)
        if (stored) {
          return JSON.parse(stored)
        }
      } catch (err) {
        console.warn('Error al cargar subcategorías desde localStorage:', err)
      }
    }
    return {
      'organoleptica': [],
      'descriptiva-afectiva': [],
      'defectos': [],
      'impresion-global': [],
    }
  }

  // Estado de la UI
  const tabActiva = useState<TabCatacion>('tab-activa', () => 'organoleptica')
  const subcategoriasPorTab = useState<SubcategoriasPorTab>('subcategorias-por-tab', cargarSubcategoriasDesdeStorage)
  const accordionAbierto = useState<string | undefined>('accordion-abierto', () => undefined)

  // Computed para obtener las subcategorías de la tab actual
  const subcategoriasActivas = computed(() => subcategoriasPorTab.value[tabActiva.value])

  /**
   * Actualiza las subcategorías de la tab actual y las guarda en localStorage
   */
  const actualizarSubcategorias = (subcategorias: Subcategoria[]) => {
    subcategoriasPorTab.value[tabActiva.value] = subcategorias
    if (import.meta.client) {
      try {
        localStorage.setItem(STORAGE_KEY_SUBCATEGORIAS, JSON.stringify(subcategoriasPorTab.value))
      } catch (err) {
        console.warn('Error al guardar subcategorías en localStorage:', err)
      }
    }
  }

  /**
   * Crea una nueva sesión de catación
   */
  const crearNuevaSesion = async (catador: string, cantidadMuestras: number) => {
    try {
      const nuevaSesion = crearSesionVacia(catador, cantidadMuestras)
      await guardar(nuevaSesion)
      // Resetear estado de UI
      tabActiva.value = 'organoleptica'
      accordionAbierto.value = undefined
      return nuevaSesion
    } catch (err) {
      console.error('Error al crear nueva sesión:', err)
      throw err
    }
  }

  /**
   * Actualiza una muestra específica y guarda en IndexedDB
   */
  const actualizarMuestra = async (muestraId: number, muestraActualizada: Partial<Muestra>) => {
    if (!sesionActiva.value) {
      throw new Error('No hay sesión activa')
    }

    try {
      const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId)

      if (!muestra) {
        throw new Error(`Muestra con ID ${muestraId} no encontrada`)
      }

      // Actualizar muestra directamente (mutación)
      Object.assign(muestra, muestraActualizada)

      // Recalcular puntaje final si hay cambios en intensidades
      if (muestraActualizada.intensidades) {
        muestra.puntajeFinal = calcularPuntajeFinal(muestra)
      }

      // Guardar en IndexedDB
      await actualizar(sesionActiva.value)
    } catch (err) {
      console.error('Error al actualizar muestra:', err)
      throw err
    }
  }

  /**
   * Actualiza un valor de intensidad específico
   */
  const actualizarIntensidad = async (
    muestraId: number,
    parametro: keyof Muestra['intensidades'],
    tipo: 'descriptiva' | 'afectiva',
    valor: number | null
  ) => {
    if (!sesionActiva.value) {
      throw new Error('No hay sesión activa')
    }

    try {
      const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId)

      if (!muestra) {
        throw new Error(`Muestra con ID ${muestraId} no encontrada`)
      }

      // Actualizar valor de intensidad directamente (mutación)
      muestra.intensidades[parametro][tipo] = valor

      // Recalcular puntaje final
      muestra.puntajeFinal = calcularPuntajeFinal(muestra)

      // Guardar en IndexedDB (pasa la sesión actual, no un clon)
      await actualizar(sesionActiva.value)
    } catch (err) {
      console.error('Error al actualizar intensidad:', err)
      throw err
    }
  }

  /**
   * Actualiza el nombre de una muestra
   */
  const actualizarNombreMuestra = async (muestraId: number, nombre: string) => {
    await actualizarMuestra(muestraId, { nombre })
  }

  /**
   * Actualiza las notas de fragancia/aroma
   */
  const actualizarFraganciaAroma = async (
    muestraId: number,
    categorias: string[],
    subcategorias: string[],
    notaEspecifica: string | null
  ) => {
    await actualizarMuestra(muestraId, {
      fraganciaAromaNotas: { categorias: categorias as any, subcategorias, notaEspecifica },
    })
  }

  /**
   * Actualiza las notas de sabor
   */
  const actualizarSabor = async (
    muestraId: number,
    categorias: string[],
    subcategorias: string[],
    notaEspecifica: string | null
  ) => {
    await actualizarMuestra(muestraId, {
      saborNotas: { categorias: categorias as any, subcategorias, notaEspecifica },
    })
  }

  /**
   * Actualiza tazas no uniformes
   */
  const actualizarTazasNoUniformes = async (muestraId: number, tazas: number[]) => {
    await actualizarMuestra(muestraId, { tazasNoUniformes: tazas })
  }

  /**
   * Actualiza tazas defectuosas
   */
  const actualizarTazasDefectuosas = async (muestraId: number, tazas: number[]) => {
    await actualizarMuestra(muestraId, { tazasDefectuosas: tazas })
  }

  /**
   * Actualiza el tipo de defecto
   */
  const actualizarDefecto = async (muestraId: number, defecto: string | null) => {
    await actualizarMuestra(muestraId, { defecto: defecto as any })
  }

  /**
   * Actualiza sensación en boca (selección única)
   */
  const actualizarSensacionBoca = async (muestraId: number, sensacion: string | null) => {
    await actualizarMuestra(muestraId, { sensacionEnBoca: sensacion as any })
  }

  /**
   * Actualiza gustos predominantes (máximo 2)
   */
  const actualizarGustosPredominantes = async (muestraId: number, gustos: string[]) => {
    if (gustos.length > 2) {
      throw new Error('Máximo 2 gustos predominantes permitidos')
    }
    if (gustos.length < 1) {
      throw new Error('Mínimo 1 gusto predominante requerido')
    }
    await actualizarMuestra(muestraId, { gustosPredominantes: gustos as any })
  }

  /**
   * Actualiza notas adicionales
   */
  const actualizarOtrasNotas = async (muestraId: number, notas: string) => {
    await actualizarMuestra(muestraId, { otrasNotas: notas })
  }

  /**
   * Obtiene una muestra específica
   */
  const obtenerMuestra = (muestraId: number): Muestra | null => {
    if (!sesionActiva.value) return null
    const muestra = sesionActiva.value.muestras.find(m => m.muestraId === muestraId)
    return muestra || null
  }

  /**
   * Verifica si una muestra está completa (tiene todos los campos requeridos)
   */
  const esMuestraCompleta = (muestra: Muestra): boolean => {
    // Verificar intensidades afectivas (son las que cuentan para el puntaje)
    const intensidadesCompletas = Object.values(muestra.intensidades).every(
      (intensidad) => intensidad.afectiva !== null
    )

    // Verificar notas de fragancia/aroma (al menos una categoría)
    const fraganciaAromaCompleta = muestra.fraganciaAromaNotas.categorias.length > 0

    // Verificar notas de sabor (al menos una categoría)
    const saborCompleto = muestra.saborNotas.categorias.length > 0

    // Verificar gustos predominantes (mínimo 1, máximo 2)
    const gustosCompletos = muestra.gustosPredominantes.length >= 1 && muestra.gustosPredominantes.length <= 2

    return intensidadesCompletas && fraganciaAromaCompleta && saborCompleto && gustosCompletos
  }

  /**
   * Obtiene el porcentaje de completitud de una muestra
   */
  const porcentajeCompletitud = (muestra: Muestra): number => {
    let total = 0
    let completados = 0

    // Intensidades afectivas (8 campos)
    total += 8
    completados += Object.values(muestra.intensidades).filter(
      (intensidad) => intensidad.afectiva !== null
    ).length

    // Intensidades descriptivas (8 campos)
    total += 8
    completados += Object.values(muestra.intensidades).filter(
      (intensidad) => intensidad.descriptiva !== null
    ).length

    // Notas fragancia/aroma (al menos una categoría)
    total += 1
    if (muestra.fraganciaAromaNotas.categorias.length > 0) completados += 1

    // Notas sabor (al menos una categoría)
    total += 1
    if (muestra.saborNotas.categorias.length > 0) completados += 1

    // Gustos predominantes
    total += 1
    if (muestra.gustosPredominantes.length >= 1) completados += 1

    return Math.round((completados / total) * 100)
  }

  /**
   * Elimina la sesión actual
   */
  const eliminarSesionActual = async () => {
    try {
      await eliminar()
      tabActiva.value = 'organoleptica'
      accordionAbierto.value = undefined
    } catch (err) {
      console.error('Error al eliminar sesión:', err)
      throw err
    }
  }

  /**
   * Exporta la sesión actual como JSON
   */
  const exportarSesion = (): string | null => {
    if (!sesionActiva.value) return null
    return JSON.stringify(sesionActiva.value, null, 2)
  }

  /**
   * Calcula estadísticas generales de la sesión
   */
  const estadisticasSesion = computed(() => {
    if (!sesionActiva.value) return null

    const muestras = sesionActiva.value.muestras
    const totalMuestras = muestras.length
    const muestrasCompletas = muestras.filter(esMuestraCompleta).length
    const promedioCompletitud = muestras.reduce((acc, m) => acc + porcentajeCompletitud(m), 0) / totalMuestras
    const puntajePromedio = muestras.reduce((acc, m) => acc + m.puntajeFinal, 0) / totalMuestras

    return {
      totalMuestras,
      muestrasCompletas,
      porcentajeCompletitud: Math.round(promedioCompletitud),
      puntajePromedio: Math.round(puntajePromedio),
    }
  })

  return {
    // Estado de la sesión
    sesionActiva,
    cargando,
    error,

    // Estado de la UI
    tabActiva,
    subcategoriasActivas,
    accordionAbierto,
    actualizarSubcategorias,

    // Estadísticas
    estadisticasSesion,

    // Métodos CRUD de sesión
    crearNuevaSesion,
    eliminarSesionActual,
    exportarSesion,

    // Métodos de actualización de muestras
    actualizarMuestra,
    actualizarIntensidad,
    actualizarNombreMuestra,
    actualizarFraganciaAroma,
    actualizarSabor,
    actualizarTazasNoUniformes,
    actualizarTazasDefectuosas,
    actualizarDefecto,
    actualizarSensacionBoca,
    actualizarGustosPredominantes,
    actualizarOtrasNotas,

    // Utilidades
    obtenerMuestra,
    esMuestraCompleta,
    porcentajeCompletitud,
  }
}
