<!-- Gráfica de Uva Pagada vs Uva en Depósito -->
<template>
  <UCard class="brand-card border border-transparent">
    <template #header>
      <div class="flex flex-col gap-3">
        <div class="flex items-center justify-between">
          <div>
            <h3 class="text-lg font-bold brand-section-title">Dinámica: Pagado vs Depósito</h3>
            <p class="text-xs text-[var(--brand-text-muted)] mt-1">
              Evolución de café pagado y en depósito
            </p>
          </div>
          <div class="flex items-center gap-2 flex-wrap">
            <UCheckbox
              v-for="tipo in tipos"
              :key="tipo.value"
              :model-value="tiposSeleccionados.includes(tipo.value)"
              @update:model-value="(checked) => toggleTipo(tipo.value, checked)"
              :label="getTipoLabel(tipo)"
              :disabled="isTipoDisabled(tipo.value)"
              size="xs"
            />
          </div>
        </div>

        <!-- Selector de Granularidad Temporal -->
        <div class="flex items-center gap-2">
          <span class="text-xs text-[var(--brand-text-muted)] uppercase tracking-wide">Granularidad:</span>
          <div class="flex items-center gap-1">
            <button
              v-for="option in granularityOptions"
              :key="option.value"
              @click="selectedGranularity = option.value"
              :class="[
                'inline-flex items-center gap-1.5 px-2.5 py-1 rounded text-xs font-medium transition-all',
                selectedGranularity === option.value
                  ? 'bg-[var(--brand-primary)] text-white shadow-sm'
                  : 'bg-[var(--brand-surface)] text-[var(--brand-text-muted)] hover:bg-[var(--brand-primary)]/10 hover:text-[var(--brand-text)]'
              ]"
            >
              <UIcon :name="option.icon" class="w-3.5 h-3.5" />
              <span>{{ option.label }}</span>
            </button>
          </div>
        </div>
      </div>
    </template>

    <div class="relative w-full" style="height: 400px;">
      <svg :viewBox="`0 0 ${width} ${height}`" class="w-full h-full" preserveAspectRatio="none">
        <!-- Grid lines -->
        <g v-for="i in 5" :key="`grid-${i}`">
          <line
            :x1="padding"
            :y1="padding + (i - 1) * (chartHeight / 4)"
            :x2="width - padding"
            :y2="padding + (i - 1) * (chartHeight / 4)"
            stroke="currentColor"
            :stroke-opacity="0.1"
            stroke-width="1"
          />
          <text
            :x="padding - 10"
            :y="padding + (i - 1) * (chartHeight / 4) + 5"
            text-anchor="end"
            class="text-xs fill-[var(--brand-text-muted)]"
          >
            {{ formatValue(maxValue - (i - 1) * (maxValue / 4)) }}
          </text>
        </g>

        <!-- Gráficas por cada tipo -->
        <g v-for="tipo in tiposActivos" :key="`tipo-${tipo.value}`">
          <!-- Area Pagado -->
          <path
            :d="getAreaPagadoPathForTipo(tipo.value)"
            :fill="getTipoColor(tipo.value)"
            fill-opacity="0.2"
          />

          <!-- Area Deposito -->
          <path
            :d="getAreaDepositoPathForTipo(tipo.value)"
            :fill="getTipoColor(tipo.value)"
            fill-opacity="0.1"
            stroke-dasharray="5,5"
          />

          <!-- Line Pagado -->
          <path
            :d="getLinePagadoPathForTipo(tipo.value)"
            :stroke="getTipoColor(tipo.value)"
            stroke-width="3"
            fill="none"
            stroke-linecap="round"
            stroke-linejoin="round"
          />

          <!-- Line Deposito -->
          <path
            :d="getLineDepositoPathForTipo(tipo.value)"
            :stroke="getTipoColor(tipo.value)"
            stroke-width="3"
            fill="none"
            stroke-linecap="round"
            stroke-linejoin="round"
            stroke-dasharray="8,4"
          />

          <!-- Points Pagado -->
          <circle
            v-for="(point, i) in getPointsPagadoForTipo(tipo.value)"
            :key="`pagado-${tipo.value}-${i}`"
            :cx="point.x"
            :cy="point.y"
            r="4"
            :fill="getTipoColor(tipo.value)"
            class="cursor-pointer hover:r-6 transition-all"
          >
            <title>{{ tipo.label }} Pagado - {{ point.label }}: {{ point.value.toFixed(2) }} {{ getTipoUnidad(tipo) }}</title>
          </circle>

          <!-- Points Deposito -->
          <circle
            v-for="(point, i) in getPointsDepositoForTipo(tipo.value)"
            :key="`deposito-${tipo.value}-${i}`"
            :cx="point.x"
            :cy="point.y"
            r="4"
            :fill="getTipoColor(tipo.value)"
            fill-opacity="0.6"
            class="cursor-pointer hover:r-6 transition-all"
          >
            <title>{{ tipo.label }} Depósito - {{ point.label }}: {{ point.value.toFixed(2) }} {{ getTipoUnidad(tipo) }}</title>
          </circle>
        </g>

        <!-- X-axis labels (distribuidos uniformemente) -->
        <g v-if="tiposActivos.length > 0">
          <text
            v-for="(point, i) in getPointsPagadoForTipo(tiposActivos[0].value)"
            :key="`label-${i}`"
            v-show="shouldShowLabel(i, getPointsPagadoForTipo(tiposActivos[0].value).length)"
            :x="point.x"
            :y="height - padding + 20"
            text-anchor="middle"
            class="text-xs fill-[var(--brand-text-muted)]"
          >
            {{ point.dateLabel }}
          </text>
        </g>
      </svg>
    </div>

    <template #footer>
      <div class="flex items-center justify-between text-xs flex-wrap gap-2">
        <div class="flex items-center gap-4 flex-wrap">
          <div v-for="tipo in tiposActivos" :key="`totales-${tipo.value}`" class="flex items-center gap-3">
            <div class="flex items-center gap-1.5">
              <div class="w-3 h-3 rounded-full" :style="{ backgroundColor: getTipoColor(tipo.value) }"></div>
              <span class="text-[var(--brand-text-muted)] text-xs">{{ tipo.label }}:</span>
            </div>
            <div class="flex items-center gap-2">
              <span class="font-bold" :style="{ color: getTipoColor(tipo.value) }">
                {{ formatValue(getTotalPagadoForTipo(tipo.value)) }} {{ getTipoUnidad(tipo) }}
              </span>
              <span class="text-[var(--brand-text-muted)]">pagado</span>
            </div>
            <div class="flex items-center gap-2">
              <span class="font-bold opacity-60" :style="{ color: getTipoColor(tipo.value) }">
                {{ formatValue(getTotalDepositoForTipo(tipo.value)) }} {{ getTipoUnidad(tipo) }}
              </span>
              <span class="text-[var(--brand-text-muted)]">depósito</span>
            </div>
          </div>
        </div>
      </div>
    </template>
  </UCard>
</template>

<script setup lang="ts">
import type { IngresoRecord } from '~/composables/useIngresosMetrics'

interface Props {
  ingresos: IngresoRecord[]
}

const props = defineProps<Props>()

const tipos = [
  { value: 'uva', label: 'Uva', unidad: 'lb' },
  { value: 'oreado', label: 'Oreado', unidad: 'qq' },
  { value: 'mojado', label: 'Mojado', unidad: 'qq' },
  { value: 'verde', label: 'Verde', unidad: 'lb' }
]

const tiposSeleccionados = ref(['uva'])

const tiposActivos = computed(() => tipos.filter(t => tiposSeleccionados.value.includes(t.value)))

// Selector de granularidad temporal
type GranularityMode = 'auto' | 'year' | 'month' | 'day' | 'hour'
const selectedGranularity = ref<GranularityMode>('auto')

const granularityOptions = [
  { value: 'auto' as GranularityMode, label: 'Auto', icon: 'i-lucide-wand-2' },
  { value: 'year' as GranularityMode, label: 'Años', icon: 'i-lucide-calendar' },
  { value: 'month' as GranularityMode, label: 'Meses', icon: 'i-lucide-calendar-days' },
  { value: 'day' as GranularityMode, label: 'Días', icon: 'i-lucide-calendar-clock' },
  { value: 'hour' as GranularityMode, label: 'Horas', icon: 'i-lucide-clock' }
]

// Determinar si estamos en modo seco (oreado o mojado seleccionado)
const modoSeco = computed(() => {
  return tiposSeleccionados.value.includes('oreado') || tiposSeleccionados.value.includes('mojado')
})

// Determinar si un tipo está deshabilitado
function isTipoDisabled(tipo: string): boolean {
  if (tipo === 'verde') {
    return modoSeco.value
  }
  if (tipo === 'oreado' || tipo === 'mojado') {
    return tiposSeleccionados.value.includes('verde')
  }
  return false
}

// Obtener label dinámico con unidad correcta
function getTipoLabel(tipo: { value: string, label: string, unidad: string }): string {
  if (tipo.value === 'uva') {
    return modoSeco.value ? `${tipo.label} (qq)` : `${tipo.label} (lb)`
  }
  return `${tipo.label} (${tipo.unidad})`
}

// Obtener unidad dinámica según el modo
function getTipoUnidad(tipo: { value: string, label: string, unidad: string }): string {
  if (tipo.value === 'uva') {
    return modoSeco.value ? 'qq' : 'lb'
  }
  return tipo.unidad
}

function toggleTipo(value: string, checked: boolean) {
  if (checked) {
    if (!tiposSeleccionados.value.includes(value)) {
      tiposSeleccionados.value.push(value)
    }
    // Si se activa verde, desactivar oreado y mojado
    if (value === 'verde') {
      tiposSeleccionados.value = tiposSeleccionados.value.filter(v => v !== 'oreado' && v !== 'mojado')
    }
    // Si se activa oreado o mojado, desactivar verde
    if (value === 'oreado' || value === 'mojado') {
      tiposSeleccionados.value = tiposSeleccionados.value.filter(v => v !== 'verde')
    }
  } else {
    tiposSeleccionados.value = tiposSeleccionados.value.filter(v => v !== value)
  }
}

const width = 1200
const height = 400
const padding = 60

const chartWidth = width - 2 * padding
const chartHeight = height - 2 * padding

interface DataPoint {
  date: Date
  value: number
  x: number
  y: number
  label: string
  dateLabel: string
}

// Función para detectar granularidad temporal
function getTimeGranularity(startDate: Date, endDate: Date): 'year' | 'month' | 'day' | 'hour' {
  // Si no es auto, usar la selección manual
  if (selectedGranularity.value !== 'auto') {
    return selectedGranularity.value
  }

  // Auto: detectar según el rango
  const diffMs = endDate.getTime() - startDate.getTime()
  const diffDays = diffMs / (1000 * 60 * 60 * 24)
  const diffMonths = diffDays / 30
  const diffYears = diffDays / 365

  if (diffYears > 2) return 'year'
  if (diffMonths > 2) return 'month'
  if (diffDays > 2) return 'day'
  return 'hour'
}

// Función para generar timestamps completos según granularidad
function generateTimeRange(startDate: Date, endDate: Date, granularity: 'year' | 'month' | 'day' | 'hour'): Date[] {
  const dates: Date[] = []
  const current = new Date(startDate)

  while (current <= endDate) {
    dates.push(new Date(current))

    switch (granularity) {
      case 'year':
        current.setFullYear(current.getFullYear() + 1)
        break
      case 'month':
        current.setMonth(current.getMonth() + 1)
        break
      case 'day':
        current.setDate(current.getDate() + 1)
        break
      case 'hour':
        current.setHours(current.getHours() + 1)
        break
    }
  }

  return dates
}

// Función para formatear fecha según granularidad
function formatDateByGranularity(date: Date, granularity: 'year' | 'month' | 'day' | 'hour'): string {
  switch (granularity) {
    case 'year':
      return date.getFullYear().toString()
    case 'month':
      return date.toLocaleDateString('es-HN', { year: 'numeric', month: 'short' })
    case 'day':
      return date.toLocaleDateString('es-HN', { day: 'numeric', month: 'short' })
    case 'hour':
      return date.toLocaleTimeString('es-HN', { hour: '2-digit', minute: '2-digit' })
  }
}

// Función para agrupar fecha según granularidad (devuelve formato ISO parseable)
function getDateKey(date: Date, granularity: 'year' | 'month' | 'day' | 'hour'): string {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  const hour = String(date.getHours()).padStart(2, '0')

  switch (granularity) {
    case 'year':
      return `${year}`
    case 'month':
      return `${year}-${month}`
    case 'day':
      return `${year}-${month}-${day}`
    case 'hour':
      return `${year}-${month}-${day}T${hour}`
  }
}

// Determinar si mostrar una etiqueta (máximo 10 etiquetas en el eje)
function shouldShowLabel(index: number, total: number): boolean {
  if (total <= 10) return true

  const maxLabels = 10
  const step = Math.ceil(total / maxLabels)

  // Siempre mostrar primera y última
  if (index === 0 || index === total - 1) return true

  // Mostrar cada N puntos
  return index % step === 0
}

// Datos pagado por tipo
const dataPagadoByTipo = computed(() => {
  const result: Record<string, DataPoint[]> = {}

  // Encontrar rango temporal solo de los tipos seleccionados
  const allDates = props.ingresos
    .filter(i => tiposSeleccionados.value.includes(i.tipo))
    .filter(i => i.created_at)
    .map(i => new Date(i.created_at!))

  if (allDates.length === 0) {
    tiposSeleccionados.value.forEach(tipo => {
      result[tipo] = []
    })
    return result
  }

  const minDate = new Date(Math.min(...allDates.map(d => d.getTime())))
  const maxDate = new Date(Math.max(...allDates.map(d => d.getTime())))
  const granularity = getTimeGranularity(minDate, maxDate)
  const timeRange = generateTimeRange(minDate, maxDate, granularity)

  tiposSeleccionados.value.forEach(tipo => {
    const ingresosFiltrados = props.ingresos
      .filter(i => i.tipo === tipo)
      .filter(i => i.estado === 'pagado')
      .filter(i => i.created_at)

    const porPeriodo = new Map<string, number>()

    ingresosFiltrados.forEach(ingreso => {
      const fecha = new Date(ingreso.created_at!)
      const key = getDateKey(fecha, granularity)
      let valor = 0

      if (tipo === 'uva') {
        valor = modoSeco.value ? ingreso.peso_neto / 500 : ingreso.peso_neto
      } else if (tipo === 'verde') {
        valor = ingreso.peso_neto
      } else {
        valor = ingreso.peso_seco
      }

      porPeriodo.set(key, (porPeriodo.get(key) || 0) + valor)
    })

    let acumulado = 0
    const puntos: DataPoint[] = []

    timeRange.forEach(fecha => {
      const key = getDateKey(fecha, granularity)
      const valor = porPeriodo.get(key) || 0
      acumulado += valor

      puntos.push({
        date: fecha,
        value: acumulado,
        x: 0,
        y: 0,
        label: key,
        dateLabel: formatDateByGranularity(fecha, granularity)
      })
    })

    result[tipo] = puntos
  })

  return result
})

// Datos depósito por tipo
const dataDepositoByTipo = computed(() => {
  const result: Record<string, DataPoint[]> = {}

  // Encontrar rango temporal solo de los tipos seleccionados
  const allDates = props.ingresos
    .filter(i => tiposSeleccionados.value.includes(i.tipo))
    .filter(i => i.created_at)
    .map(i => new Date(i.created_at!))

  if (allDates.length === 0) {
    tiposSeleccionados.value.forEach(tipo => {
      result[tipo] = []
    })
    return result
  }

  const minDate = new Date(Math.min(...allDates.map(d => d.getTime())))
  const maxDate = new Date(Math.max(...allDates.map(d => d.getTime())))
  const granularity = getTimeGranularity(minDate, maxDate)
  const timeRange = generateTimeRange(minDate, maxDate, granularity)

  tiposSeleccionados.value.forEach(tipo => {
    const todosFiltrados = props.ingresos
      .filter(i => i.tipo === tipo)
      .filter(i => i.created_at)

    const pagadosFiltrados = props.ingresos
      .filter(i => i.tipo === tipo)
      .filter(i => i.estado === 'pagado')
      .filter(i => i.created_at)

    const totalPorPeriodo = new Map<string, number>()
    const pagadoPorPeriodo = new Map<string, number>()

    todosFiltrados.forEach(ingreso => {
      const fecha = new Date(ingreso.created_at!)
      const key = getDateKey(fecha, granularity)
      let valor = 0

      if (tipo === 'uva') {
        valor = modoSeco.value ? ingreso.peso_neto / 500 : ingreso.peso_neto
      } else if (tipo === 'verde') {
        valor = ingreso.peso_neto
      } else {
        valor = ingreso.peso_seco
      }

      totalPorPeriodo.set(key, (totalPorPeriodo.get(key) || 0) + valor)
    })

    pagadosFiltrados.forEach(ingreso => {
      const fecha = new Date(ingreso.created_at!)
      const key = getDateKey(fecha, granularity)
      let valor = 0

      if (tipo === 'uva') {
        valor = modoSeco.value ? ingreso.peso_neto / 500 : ingreso.peso_neto
      } else if (tipo === 'verde') {
        valor = ingreso.peso_neto
      } else {
        valor = ingreso.peso_seco
      }

      pagadoPorPeriodo.set(key, (pagadoPorPeriodo.get(key) || 0) + valor)
    })

    let acumuladoTotal = 0
    let acumuladoPagado = 0
    const puntos: DataPoint[] = []

    timeRange.forEach(fecha => {
      const key = getDateKey(fecha, granularity)
      acumuladoTotal += totalPorPeriodo.get(key) || 0
      acumuladoPagado += pagadoPorPeriodo.get(key) || 0
      const deposito = acumuladoTotal - acumuladoPagado

      puntos.push({
        date: fecha,
        value: deposito,
        x: 0,
        y: 0,
        label: key,
        dateLabel: formatDateByGranularity(fecha, granularity)
      })
    })

    result[tipo] = puntos
  })

  return result
})

const maxValue = computed(() => {
  let max = 0

  Object.values(dataPagadoByTipo.value).forEach(puntos => {
    if (puntos.length > 0) {
      const maxPagado = Math.max(...puntos.map(p => p.value))
      if (maxPagado > max) max = maxPagado
    }
  })

  Object.values(dataDepositoByTipo.value).forEach(puntos => {
    if (puntos.length > 0) {
      const maxDeposito = Math.max(...puntos.map(p => p.value))
      if (maxDeposito > max) max = maxDeposito
    }
  })

  return max * 1.1 || 100
})

function getTipoColor(tipo: string) {
  const tipoConfig = tipos.find(t => t.value === tipo)
  return tipoConfig?.value === 'uva' ? 'var(--coffee-uva)' :
         tipoConfig?.value === 'oreado' ? 'var(--coffee-oreado)' :
         tipoConfig?.value === 'mojado' ? 'var(--coffee-mojado)' : 'var(--coffee-verde)'
}

function getPointsPagadoForTipo(tipo: string) {
  const data = dataPagadoByTipo.value[tipo]
  if (!data || data.length === 0) return []

  return data.map((point, i) => {
    const x = padding + (i / (data.length - 1 || 1)) * chartWidth
    const y = height - padding - (point.value / maxValue.value) * chartHeight

    return { ...point, x, y }
  })
}

function getPointsDepositoForTipo(tipo: string) {
  const data = dataDepositoByTipo.value[tipo]
  if (!data || data.length === 0) return []

  return data.map((point, i) => {
    const x = padding + (i / (data.length - 1 || 1)) * chartWidth
    const y = height - padding - (point.value / maxValue.value) * chartHeight

    return { ...point, x, y }
  })
}

function getLinePagadoPathForTipo(tipo: string) {
  const points = getPointsPagadoForTipo(tipo)
  if (points.length === 0) return ''

  return points.map((point, i) => {
    return i === 0 ? `M ${point.x} ${point.y}` : `L ${point.x} ${point.y}`
  }).join(' ')
}

function getLineDepositoPathForTipo(tipo: string) {
  const points = getPointsDepositoForTipo(tipo)
  if (points.length === 0) return ''

  return points.map((point, i) => {
    return i === 0 ? `M ${point.x} ${point.y}` : `L ${point.x} ${point.y}`
  }).join(' ')
}

function getAreaPagadoPathForTipo(tipo: string) {
  const points = getPointsPagadoForTipo(tipo)
  if (points.length === 0) return ''

  const linePart = points.map((point, i) => {
    return i === 0 ? `M ${point.x} ${point.y}` : `L ${point.x} ${point.y}`
  }).join(' ')

  const lastPoint = points[points.length - 1]
  const firstPoint = points[0]

  if (!lastPoint || !firstPoint) return ''

  return `${linePart} L ${lastPoint.x} ${height - padding} L ${firstPoint.x} ${height - padding} Z`
}

function getAreaDepositoPathForTipo(tipo: string) {
  const points = getPointsDepositoForTipo(tipo)
  if (points.length === 0) return ''

  const linePart = points.map((point, i) => {
    return i === 0 ? `M ${point.x} ${point.y}` : `L ${point.x} ${point.y}`
  }).join(' ')

  const lastPoint = points[points.length - 1]
  const firstPoint = points[0]

  if (!lastPoint || !firstPoint) return ''

  return `${linePart} L ${lastPoint.x} ${height - padding} L ${firstPoint.x} ${height - padding} Z`
}

function getTotalPagadoForTipo(tipo: string) {
  const data = dataPagadoByTipo.value[tipo]
  if (!data || data.length === 0) return 0
  return data[data.length - 1]?.value || 0
}

function getTotalDepositoForTipo(tipo: string) {
  const data = dataDepositoByTipo.value[tipo]
  if (!data || data.length === 0) return 0
  return data[data.length - 1]?.value || 0
}

function formatValue(value: number): string {
  if (value >= 1000) {
    return (value / 1000).toFixed(1) + 'k'
  }
  return value.toFixed(0)
}
</script>
