<script setup>
import { useDisplay, useTheme } from 'vuetify'
import { hexToRgb } from '@layouts/utils'
import { computed, onMounted, onUnmounted, ref, nextTick, watch } from 'vue'

const props = defineProps({
  apiUrl: {
    type: String,
    required: true
  },
  apiHeaders: {
    type: Object,
    default: () => ({})
  },
  dataKey: {
    type: String,
    default: 'data'
  },
  sumFields: {
    type: Array,
    default: () => ['cost']
  },
  sumField: {
    type: String,
    default: 'cost'
  },
  nameField: {
    type: String,
    default: 'name'
  },
  title: {
    type: String,
    default: 'Generated Leads'
  },
  subtitle: {
    type: String,
    default: 'Total Summary'
  },
  currency: {
    type: String,
    default: '$'
  },
  showPercentage: {
    type: Boolean,
    default: true
  },
  previousValue: {
    type: Number,
    default: null
  },
  displayMode: {
    type: String,
    default: 'single',
    validator: (value) => ['single', 'multiple'].includes(value)
  },
  donutColors: {
    type: Array,
    default: () => ['success']
  },
  progress: {
    type: Number,
    default: null
  },
  target: {
    type: Number,
    default: null
  },
  refreshInterval: {
    type: Number,
    default: 0
  },
  roundNumbers: {
    type: Boolean,
    default: false
  }
})

const emit = defineEmits(['dataLoaded', 'error', 'loading'])

const vuetifyTheme = useTheme()
const display = useDisplay()
const cardRef = ref(null)
const cardWidth = ref(300)

const isLoading = ref(false)
const error = ref(null)
const apiData = ref([])
const totalValue = ref(0)
const multipleValues = ref({})
const previousTotal = ref(0)
const refreshTimer = ref(null)

const effectiveSumFields = computed(() => {
  if (props.displayMode === 'multiple' && props.sumFields.length > 0) {
    return props.sumFields
  }
  return [props.sumField]
})

const fetchData = async () => {
  try {
    isLoading.value = true
    error.value = null
    emit('loading', true)

    const response = await fetch(props.apiUrl, {
      headers: {
        'Content-Type': 'application/json',
        ...props.apiHeaders
      }
    })

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const responseData = await response.json()
    const dataArray = responseData[props.dataKey] || responseData

    if (!Array.isArray(dataArray)) {
      throw new Error('Response data is not an array')
    }

    if (totalValue.value > 0) {
      previousTotal.value = totalValue.value
    }

    apiData.value = dataArray

    const newMultipleValues = {}
    let newTotalValue = 0

    effectiveSumFields.value.forEach(field => {
      const fieldTotal = dataArray.reduce((sum, item) => {
        const value = parseFloat(item[field]) || 0
        return sum + value
      }, 0)

      newMultipleValues[field] = props.roundNumbers ? Math.round(fieldTotal) : fieldTotal

      if (field === effectiveSumFields.value[0]) {
        newTotalValue = newMultipleValues[field]
      }
    })

    if (props.displayMode === 'multiple') {
      newTotalValue = Object.values(newMultipleValues).reduce((sum, val) => sum + val, 0)
    }

    multipleValues.value = newMultipleValues
    totalValue.value = newTotalValue

    emit('dataLoaded', {
      data: dataArray,
      total: newTotalValue,
      breakdown: newMultipleValues,
      count: dataArray.length
    })

  } catch (err) {
    error.value = err.message
    emit('error', err.message)
  } finally {
    isLoading.value = false
    emit('loading', false)
  }
}

const setupRefresh = () => {
  if (refreshTimer.value) {
    clearInterval(refreshTimer.value)
  }

  if (props.refreshInterval > 0) {
    refreshTimer.value = setInterval(fetchData, props.refreshInterval)
  }
}

const formatCurrency = (value) => {
  if (typeof value !== 'number') return `${props.currency}0`

  const roundedValue = Math.round(value)

  return `${props.currency}${roundedValue.toLocaleString('en-US')}`
}

const formatFieldName = (field) => {
  return field.charAt(0).toUpperCase() + field.slice(1).replace(/([A-Z])/g, ' $1')
}

const formattedTotal = computed(() => {
  if (isLoading.value) return '...'
  if (error.value) return 'Error'

  return formatCurrency(totalValue.value)
})

const formattedBreakdown = computed(() => {
  if (isLoading.value || error.value || props.displayMode === 'single') return []

  return effectiveSumFields.value.map(field => ({
    field,
    label: formatFieldName(field),
    value: multipleValues.value[field] || 0,
    formatted: formatCurrency(multipleValues.value[field] || 0)
  }))
})

const percentageChange = computed(() => {
  if (!props.showPercentage || isLoading.value || error.value) return null

  let baseValue = props.previousValue || previousTotal.value

  if (!baseValue || baseValue === 0) return null

  const change = ((totalValue.value - baseValue) / baseValue) * 100
  return {
    value: Math.abs(change).toFixed(1),
    isPositive: change >= 0
  }
})

const calculatedProgress = computed(() => {
  if (props.progress !== null) return props.progress
  if (!props.target || props.target === 0) return 75

  return Math.min(Math.max((totalValue.value / props.target) * 100, 0), 100)
})

const updateCardWidth = () => {
  if (cardRef.value && typeof cardRef.value.getBoundingClientRect === 'function') {
    try {
      const rect = cardRef.value.getBoundingClientRect()
      const newWidth = rect.width
      if (newWidth > 0 && Math.abs(newWidth - cardWidth.value) > 5) {
        cardWidth.value = newWidth
      }
    } catch (error) {
      console.warn('Error getting card dimensions:', error)
    }
  }
}

onMounted(async () => {
  await nextTick()

  setTimeout(() => {
    updateCardWidth()
  }, 100)

  window.addEventListener('resize', updateCardWidth)

  await fetchData()

  setupRefresh()
})

onUnmounted(() => {
  window.removeEventListener('resize', updateCardWidth)
  if (refreshTimer.value) {
    clearInterval(refreshTimer.value)
  }
})

watch(() => props.apiUrl, () => {
  fetchData()
})

watch(() => props.refreshInterval, () => {
  setupRefresh()
})

const chartSeries = computed(() => [calculatedProgress.value, 100 - calculatedProgress.value])

const processColors = (colors) => {
  const currentTheme = vuetifyTheme.current.value.colors
  return colors.map(color => {
    if (typeof color === 'string' && currentTheme[color]) {
      return currentTheme[color]
    }
    return color
  })
}

const chartSize = computed(() => {
  const width = cardWidth.value
  const breakpoints = {
    xs: display.xs.value,
    sm: display.sm.value,
    md: display.md.value
  }

  let size = 120

  if (breakpoints.xs) {
    size = Math.min(width * 0.35, 120)
  } else if (breakpoints.sm) {
    size = Math.min(width * 0.4, 150)
  } else if (width <= 400) {
    size = Math.min(width * 0.4, 160)
  } else if (width <= 600) {
    size = Math.min(width * 0.35, 200)
  } else {
    size = Math.min(width * 0.3, 240)
  }

  size = Math.max(size, 100)

  return { width: size, height: size }
})

const textSizes = computed(() => {
  const width = cardWidth.value

  if (display.xs.value || width < 300) {
    return {
      title: 'text-body-2',
      subtitle: 'text-caption',
      mainNumber: 'text-h6',
      percentage: 'text-caption',
      breakdown: 'text-caption'
    }
  } else if (display.sm.value || width < 450) {
    return {
      title: 'text-body-1',
      subtitle: 'text-body-2',
      mainNumber: 'text-h5',
      percentage: 'text-body-2',
      breakdown: 'text-body-2'
    }
  } else if (width < 600) {
    return {
      title: 'text-h6',
      subtitle: 'text-body-2',
      mainNumber: 'text-h4',
      percentage: 'text-body-1',
      breakdown: 'text-body-2'
    }
  } else {
    return {
      title: 'text-h5',
      subtitle: 'text-body-1',
      mainNumber: 'text-h3',
      percentage: 'text-body-1',
      breakdown: 'text-body-1'
    }
  }
})

const chartOptions = computed(() => {
  const currentTheme = vuetifyTheme.current.value.colors
  const variableTheme = vuetifyTheme.current.value.variables
  const width = cardWidth.value
  const chartSizeValue = chartSize.value.width

  const defaultDonutColors = [currentTheme.primary]
  const usedDonutColors = props.donutColors.length
    ? processColors(props.donutColors)
    : defaultDonutColors

  const headingColor = `rgba(${hexToRgb(currentTheme['on-background'])},${variableTheme['high-emphasis-opacity']})`
  const backgroundCircleColor = `rgba(${hexToRgb(usedDonutColors[0])}, 0.15)`

  const valueFontSize = chartSizeValue < 120 ? '0.9rem' :
    chartSizeValue < 160 ? '1.2rem' :
      chartSizeValue < 200 ? '1.4rem' : '1.6rem'

  const labelFontSize = chartSizeValue < 120 ? '0.7rem' :
    chartSizeValue < 160 ? '0.8rem' :
      chartSizeValue < 200 ? '0.9rem' : '1rem'

  const donutSize = chartSizeValue < 130 ? '60%' :
    chartSizeValue < 180 ? '65%' : '70%'

  return {
    chart: {
      parentHeightOffset: 0,
      type: 'donut',
      sparkline: { enabled: false },
      animations: {
        enabled: true,
        easing: 'easeinout',
        speed: 800,
        dynamicAnimation: {
          enabled: true,
          speed: 350
        }
      }
    },
    labels: ['Progress', 'Remaining'],
    colors: [...usedDonutColors, backgroundCircleColor],
    stroke: { width: 0 },
    dataLabels: { enabled: false },
    legend: { show: false },
    tooltip: {
      enabled: true,
      theme: vuetifyTheme.current.value.dark ? 'dark' : 'light',
      style: {
        fontSize: chartSizeValue < 140 ? '11px' : '13px'
      }
    },
    grid: {
      padding: { top: 0, bottom: 0, right: 0, left: 0 }
    },
    states: {
      hover: {
        filter: { type: 'none' }
      }
    },
    plotOptions: {
      pie: {
        startAngle: -90,
        endAngle: 270,
        donut: {
          size: donutSize,
          background: 'transparent',
          labels: {
            show: true,
            value: {
              show: true,
              fontSize: valueFontSize,
              fontFamily: 'Public Sans',
              color: headingColor,
              fontWeight: 600,
              offsetY: chartSizeValue < 130 ? -1 : 0,
              formatter(val) {
                return `${Math.round(val)}%`
              },
            },
            name: { show: false },
            total: {
              show: true,
              showAlways: true,
              color: usedDonutColors[0],
              fontSize: labelFontSize,
              label: 'Progress',
              fontFamily: 'Public Sans',
              fontWeight: 500,
              formatter() {
                return `${Math.round(calculatedProgress.value)}%`
              },
            },
          },
        },
      },
    },
    responsive: []
  }
})

const cardBackgroundStyle = computed(() => {
  const defaultDonutColors = [vuetifyTheme.current.value.colors.primary]
  const colors = props.donutColors.length ? processColors(props.donutColors) : defaultDonutColors

  const createGradientColor = (color, opacity = 0.08) => {
    if (color.includes('rgba')) {
      return color.replace(/[\d\.]+\)$/g, `${opacity})`)
    }
    if (color.startsWith('#')) {
      return `rgba(${hexToRgb(color)}, ${opacity})`
    }
    if (color.includes('rgb')) {
      return color.replace('rgb', 'rgba').replace(')', `, ${opacity})`)
    }
    return `rgba(${hexToRgb(color)}, ${opacity})`
  }

  const gradientColors = colors.map((color, index) =>
    createGradientColor(color, index === 0 ? 0.1 : 0.03)
  )

  return {
    background: `linear-gradient(135deg, 
      ${gradientColors[0]} 0%, 
      ${gradientColors[1] || createGradientColor(colors[0], 0.05)} 50%,
      ${gradientColors[2] || createGradientColor(colors[0], 0.02)} 100%)`
  }
})

const layoutClasses = computed(() => {
  const width = cardWidth.value

  return {
    cardPadding: display.xs.value ? 'pa-3' :
      display.sm.value ? 'pa-4' :
        width < 400 ? 'pa-4' : 'pa-5',
    textSpacing: display.xs.value ? 'me-2' :
      display.sm.value ? 'me-3' :
        width < 400 ? 'me-3' : 'me-4',
    iconSize: display.xs.value ? 14 :
      display.sm.value ? 16 :
        width < 400 ? 16 : 18,
    itemSpacing: display.xs.value ? 'mb-2' :
      width < 400 ? 'mb-3' : 'mb-3'
  }
})

defineExpose({
  refresh: fetchData,
  getData: () => apiData.value,
  getTotal: () => totalValue.value,
  getBreakdown: () => multipleValues.value
})
</script>

<template>
  <VCard ref="cardRef" class="overflow-visible" :style="cardBackgroundStyle">
    <VCardText class="d-flex align-center justify-space-between" :class="layoutClasses.cardPadding">
      <div class="d-flex flex-column flex-grow-1 flex-shrink-1" :class="layoutClasses.textSpacing"
        style="min-width: 0;">
        <div :class="layoutClasses.itemSpacing">
          <h5 class="text-no-wrap font-weight-medium text-truncate" :class="textSizes.title" style="line-height: 1.2;">
            {{ title }}
          </h5>
          <div class="text-medium-emphasis text-truncate" :class="textSizes.subtitle" style="line-height: 1.1;">
            {{ subtitle }}
          </div>
        </div>

        <div>
          <template v-if="isLoading">
            <VSkeletonLoader type="text" :class="[textSizes.mainNumber, layoutClasses.itemSpacing]" width="120" />
            <VSkeletonLoader type="text" :class="textSizes.percentage" width="60" />
          </template>

          <template v-else-if="error">
            <h3 class="font-weight-bold text-error" :class="[textSizes.mainNumber, layoutClasses.itemSpacing]"
              style="line-height: 1.1;">
              Error
            </h3>
            <div class="d-flex align-center">
              <VIcon icon="tabler-alert-circle" color="error" :size="layoutClasses.iconSize"
                class="me-1 flex-shrink-0" />
              <span class="font-weight-medium text-no-wrap text-error" :class="textSizes.percentage">
                Failed to load
              </span>
            </div>
          </template>

          <template v-else>
            <h3 class="font-weight-bold" :class="[textSizes.mainNumber, layoutClasses.itemSpacing]"
              style="line-height: 1.1;">
              {{ formattedTotal }}
            </h3>

            <div v-if="displayMode === 'multiple' && formattedBreakdown.length > 1" class="mb-2">
              <div v-for="item in formattedBreakdown" :key="item.field"
                class="d-flex justify-space-between align-center mb-1">
                <span class="text-medium-emphasis" :class="textSizes.breakdown">
                  {{ item.label }}:
                </span>
                <span class="font-weight-medium" :class="textSizes.breakdown">
                  {{ item.formatted }}
                </span>
              </div>
              <VDivider class="my-2 opacity-60" />
            </div>

            <div v-if="percentageChange" class="d-flex align-center">
              <VIcon :icon="percentageChange.isPositive ? 'tabler-chevron-up' : 'tabler-chevron-down'" :color="percentageChange.isPositive ?
                (props.donutColors.length ? processColors(props.donutColors)[0] : vuetifyTheme.current.value.colors.primary) :
                vuetifyTheme.current.value.colors.error" :size="layoutClasses.iconSize" class="me-1 flex-shrink-0" />
              <span class="font-weight-medium text-no-wrap" :class="textSizes.percentage" :style="{
                color: percentageChange.isPositive ?
                  (props.donutColors.length ? processColors(props.donutColors)[0] : vuetifyTheme.current.value.colors.primary) :
                  vuetifyTheme.current.value.colors.error
              }">
                {{ percentageChange.value }}%
              </span>
            </div>
            <div v-else-if="showPercentage" class="d-flex align-center">
              <VIcon icon="tabler-list"
                :color="props.donutColors.length ? processColors(props.donutColors)[0] : vuetifyTheme.current.value.colors.primary"
                :size="layoutClasses.iconSize" class="me-1 flex-shrink-0" />
              <span class="font-weight-medium text-no-wrap text-medium-emphasis" :class="textSizes.percentage">
                {{ apiData.length }} leads
              </span>
            </div>
          </template>
        </div>
      </div>

      <div class="d-flex align-center justify-center flex-shrink-0">
        <VueApexCharts v-if="!isLoading && !error" :options="chartOptions" :series="chartSeries"
          :height="chartSize.height" :width="chartSize.width" />
        <VSkeletonLoader v-else-if="isLoading" type="avatar" :width="chartSize.width" :height="chartSize.height" />
        <div v-else class="d-flex align-center justify-center"
          :style="{ width: chartSize.width + 'px', height: chartSize.height + 'px' }">
          <VIcon icon="tabler-alert-circle" color="error" :size="chartSize.width * 0.3" />
        </div>
      </div>
    </VCardText>
  </VCard>
</template>