'use client'

import { useState, useMemo, useRef, useCallback } from 'react'
import { useTheme } from '@ciphera-net/ui'
import {
  AreaChart,
  Area,
  XAxis,
  YAxis,
  CartesianGrid,
  Tooltip,
  ResponsiveContainer,
} from 'recharts'
import type { TooltipProps } from 'recharts'
import { formatNumber, formatDuration, formatUpdatedAgo } from '@ciphera-net/ui'
import { ArrowUpRightIcon, ArrowDownRightIcon, BarChartIcon, Select, DownloadIcon } from '@ciphera-net/ui'
import { Checkbox } from '@ciphera-net/ui'

const COLORS = {
  brand: 'var(--color-brand-orange)',
  success: 'var(--color-success)',
  danger: 'var(--color-error)',
}

const CHART_COLORS_LIGHT = {
  border: 'var(--color-neutral-200)',
  grid: 'var(--color-neutral-100)',
  text: 'var(--color-neutral-900)',
  textMuted: 'var(--color-neutral-500)',
  axis: 'var(--color-neutral-400)',
  tooltipBg: '#ffffff',
  tooltipBorder: 'var(--color-neutral-200)',
}

const CHART_COLORS_DARK = {
  border: 'var(--color-neutral-700)',
  grid: 'var(--color-neutral-800)',
  text: 'var(--color-neutral-50)',
  textMuted: 'var(--color-neutral-400)',
  axis: 'var(--color-neutral-500)',
  tooltipBg: 'var(--color-neutral-800)',
  tooltipBorder: 'var(--color-neutral-700)',
}

export interface DailyStat {
  date: string
  pageviews: number
  visitors: number
  bounce_rate: number
  avg_duration: number
}

interface Stats {
  pageviews: number
  visitors: number
  bounce_rate: number
  avg_duration: number
}

interface ChartProps {
  data: DailyStat[]
  prevData?: DailyStat[]
  stats: Stats
  prevStats?: Stats
  interval: 'minute' | 'hour' | 'day' | 'month'
  dateRange: { start: string, end: string }
  todayInterval: 'minute' | 'hour'
  setTodayInterval: (interval: 'minute' | 'hour') => void
  multiDayInterval: 'hour' | 'day'
  setMultiDayInterval: (interval: 'hour' | 'day') => void
  onExportChart?: () => void
  lastUpdatedAt?: number | null
}

type MetricType = 'pageviews' | 'visitors' | 'bounce_rate' | 'avg_duration'

// ─── Helpers ─────────────────────────────────────────────────────────

function formatAxisValue(value: number): string {
  if (value >= 1e6) return `${+(value / 1e6).toFixed(1)}M`
  if (value >= 1000) return `${+(value / 1000).toFixed(1)}k`
  if (!Number.isInteger(value)) return value.toFixed(1)
  return String(value)
}

function formatAxisDuration(seconds: number): string {
  if (!seconds) return '0s'
  const m = Math.floor(seconds / 60)
  const s = Math.floor(seconds % 60)
  if (m > 0) return s > 0 ? `${m}m${s}s` : `${m}m`
  return `${s}s`
}

function getPrevDateRangeLabel(dateRange: { start: string; end: string }): string {
  const startDate = new Date(dateRange.start)
  const endDate = new Date(dateRange.end)
  const duration = endDate.getTime() - startDate.getTime()

  if (duration === 0) {
    const prev = new Date(startDate.getTime() - 24 * 60 * 60 * 1000)
    return prev.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
  }

  const prevEnd = new Date(startDate.getTime() - 24 * 60 * 60 * 1000)
  const prevStart = new Date(prevEnd.getTime() - duration)
  const fmt = (d: Date) => d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
  return `${fmt(prevStart)} – ${fmt(prevEnd)}`
}

function getTrendContext(dateRange: { start: string; end: string }): string {
  const startDate = new Date(dateRange.start)
  const endDate = new Date(dateRange.end)
  const duration = endDate.getTime() - startDate.getTime()

  if (duration === 0) return 'vs yesterday'
  const days = Math.round(duration / (24 * 60 * 60 * 1000))
  if (days === 1) return 'vs yesterday'
  return `vs previous ${days} days`
}

// ─── Tooltip ─────────────────────────────────────────────────────────

function ChartTooltip({
  active,
  payload,
  label,
  metric,
  metricLabel,
  formatNumberFn,
  showComparison,
  prevPeriodLabel,
  colors,
}: {
  active?: boolean
  payload?: Array<{ payload: Record<string, number>; value: number; dataKey?: string }>
  label?: string
  metric: MetricType
  metricLabel: string
  formatNumberFn: (n: number) => string
  showComparison: boolean
  prevPeriodLabel?: string
  colors: typeof CHART_COLORS_LIGHT
}) {
  if (!active || !payload?.length || !label) return null

  const current = payload.find((p) => p.dataKey === metric) ?? payload[payload.length - 1]
  const value = Number(current?.value ?? current?.payload?.[metric] ?? 0)

  const prevKey = metric === 'visitors' ? 'prevVisitors' : metric === 'pageviews' ? 'prevPageviews' : metric === 'bounce_rate' ? 'prevBounceRate' : 'prevAvgDuration'
  const prev = current?.payload?.[prevKey]

  const hasPrev = showComparison && prev != null
  const delta = hasPrev && prev > 0 ? Math.round(((value - prev) / prev) * 100) : null

  const formatValue = (v: number) => {
    if (metric === 'bounce_rate') return `${Math.round(v)}%`
    if (metric === 'avg_duration') return formatDuration(v)
    return formatNumberFn(v)
  }

  return (
    <div
      className="rounded-lg border px-3.5 py-2.5 shadow-lg"
      style={{ backgroundColor: colors.tooltipBg, borderColor: colors.tooltipBorder }}
    >
      <div className="text-[11px] font-medium mb-1" style={{ color: colors.textMuted }}>
        {label}
      </div>
      <div className="flex items-baseline gap-1.5">
        <span className="text-sm font-bold" style={{ color: colors.text }}>
          {formatValue(value)}
        </span>
        <span className="text-[11px]" style={{ color: colors.textMuted }}>
          {metricLabel}
        </span>
      </div>
      {hasPrev && (
        <div className="mt-1 flex items-center gap-1.5 text-[11px]" style={{ color: colors.textMuted }}>
          <span>vs {formatValue(prev)} {prevPeriodLabel ? `(${prevPeriodLabel})` : ''}</span>
          {delta !== null && (
            <span
              className="font-medium"
              style={{
                color: delta > 0 ? (metric === 'bounce_rate' ? COLORS.danger : COLORS.success) : delta < 0 ? (metric === 'bounce_rate' ? COLORS.success : COLORS.danger) : colors.textMuted,
              }}
            >
              {delta > 0 ? '+' : ''}{delta}%
            </span>
          )}
        </div>
      )}
    </div>
  )
}

// ─── Chart Component ─────────────────────────────────────────────────

export default function Chart({
  data,
  prevData,
  stats,
  prevStats,
  interval,
  dateRange,
  todayInterval,
  setTodayInterval,
  multiDayInterval,
  setMultiDayInterval,
  onExportChart,
  lastUpdatedAt,
}: ChartProps) {
  const [metric, setMetric] = useState<MetricType>('visitors')
  const [showComparison, setShowComparison] = useState(false)
  const chartContainerRef = useRef<HTMLDivElement>(null)
  const { resolvedTheme } = useTheme()

  const handleExportChart = useCallback(async () => {
    if (onExportChart) { onExportChart(); return }
    if (!chartContainerRef.current) return
    try {
      const { toPng } = await import('html-to-image')
      const dataUrl = await toPng(chartContainerRef.current, {
        cacheBust: true,
        backgroundColor: resolvedTheme === 'dark' ? 'var(--color-neutral-900)' : '#ffffff',
      })
      const link = document.createElement('a')
      link.download = `chart-${dateRange.start}-${dateRange.end}.png`
      link.href = dataUrl
      link.click()
    } catch { /* noop */ }
  }, [onExportChart, dateRange, resolvedTheme])

  const colors = useMemo(
    () => (resolvedTheme === 'dark' ? CHART_COLORS_DARK : CHART_COLORS_LIGHT),
    [resolvedTheme]
  )

  // ─── Data ──────────────────────────────────────────────────────────

  const chartData = data.map((item, i) => {
    const prevItem = prevData?.[i]

    let formattedDate: string
    if (interval === 'minute') {
      formattedDate = new Date(item.date).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })
    } else if (interval === 'hour') {
      const d = new Date(item.date)
      const isMidnight = d.getHours() === 0 && d.getMinutes() === 0
      formattedDate = isMidnight
        ? d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + ' 12:00 AM'
        : d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + ', ' + d.toLocaleTimeString('en-US', { hour: 'numeric', minute: 'numeric' })
    } else {
      formattedDate = new Date(item.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
    }

    return {
      date: formattedDate,
      originalDate: item.date,
      pageviews: item.pageviews,
      visitors: item.visitors,
      bounce_rate: item.bounce_rate,
      avg_duration: item.avg_duration,
      prevPageviews: prevItem?.pageviews,
      prevVisitors: prevItem?.visitors,
      prevBounceRate: prevItem?.bounce_rate,
      prevAvgDuration: prevItem?.avg_duration,
    }
  })

  // ─── Metrics ───────────────────────────────────────────────────────

  const calculateTrend = (current: number, previous?: number) => {
    if (!previous) return null
    if (previous === 0) return current > 0 ? 100 : 0
    return Math.round(((current - previous) / previous) * 100)
  }

  const metrics = [
    { id: 'visitors' as const, label: 'Unique Visitors', value: formatNumber(stats.visitors), trend: calculateTrend(stats.visitors, prevStats?.visitors), invertTrend: false },
    { id: 'pageviews' as const, label: 'Total Pageviews', value: formatNumber(stats.pageviews), trend: calculateTrend(stats.pageviews, prevStats?.pageviews), invertTrend: false },
    { id: 'bounce_rate' as const, label: 'Bounce Rate', value: `${Math.round(stats.bounce_rate)}%`, trend: calculateTrend(stats.bounce_rate, prevStats?.bounce_rate), invertTrend: true },
    { id: 'avg_duration' as const, label: 'Visit Duration', value: formatDuration(stats.avg_duration), trend: calculateTrend(stats.avg_duration, prevStats?.avg_duration), invertTrend: false },
  ]

  const activeMetric = metrics.find((m) => m.id === metric) || metrics[0]
  const metricLabel = activeMetric.label
  const prevPeriodLabel = prevData?.length ? getPrevDateRangeLabel(dateRange) : ''
  const trendContext = getTrendContext(dateRange)

  const hasPrev = !!(prevData?.length && showComparison)
  const hasData = data.length > 0
  const hasAnyNonZero = hasData && chartData.some((d) => (d[metric] as number) > 0)

  // Count metrics should never show decimal Y-axis ticks
  const isCountMetric = metric === 'visitors' || metric === 'pageviews'

  // ─── X-Axis Ticks ─────────────────────────────────────────────────

  const midnightTicks = interval === 'hour'
    ? (() => {
        const t = chartData
          .filter((_, i) => { const d = new Date(data[i].date); return d.getHours() === 0 && d.getMinutes() === 0 })
          .map((c) => c.date)
        return t.length > 0 ? t : undefined
      })()
    : undefined

  const dayTicks = interval === 'day' && chartData.length > 0 ? chartData.map((c) => c.date) : undefined

  // ─── Trend Badge ──────────────────────────────────────────────────

  function TrendBadge({ trend, invert }: { trend: number | null; invert: boolean }) {
    if (trend === null) return <span className="text-neutral-400 dark:text-neutral-500">—</span>
    const effective = invert ? -trend : trend
    const isPositive = effective > 0
    const isNegative = effective < 0
    return (
      <span className={`inline-flex items-center text-xs font-medium ${isPositive ? 'text-emerald-600 dark:text-emerald-400' : isNegative ? 'text-red-500 dark:text-red-400' : 'text-neutral-400'}`}>
        {isPositive ? <ArrowUpRightIcon className="w-3 h-3 mr-0.5" /> : isNegative ? <ArrowDownRightIcon className="w-3 h-3 mr-0.5" /> : null}
        {Math.abs(trend)}%
      </span>
    )
  }

  // ─── Render ────────────────────────────────────────────────────────

  return (
    <div
      ref={chartContainerRef}
      className="bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-2xl overflow-hidden relative"
      role="region"
      aria-label={`Analytics chart showing ${metricLabel} over time`}
    >
      {/* Stat Cards */}
      <div className="grid grid-cols-2 md:grid-cols-4 divide-x divide-neutral-200 dark:divide-neutral-800 border-b border-neutral-200 dark:border-neutral-800">
        {metrics.map((item) => {
          const isActive = metric === item.id
          return (
            <button
              key={item.id}
              type="button"
              onClick={() => setMetric(item.id)}
              aria-pressed={isActive}
              aria-label={`Show ${item.label} chart`}
              className={`p-4 sm:px-6 sm:py-5 text-left transition-colors relative cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange/50 ${isActive ? 'bg-neutral-50 dark:bg-neutral-800/40' : 'hover:bg-neutral-50/50 dark:hover:bg-neutral-800/20'}`}
            >
              <div className={`text-[11px] font-semibold uppercase tracking-wider mb-1.5 ${isActive ? 'text-neutral-900 dark:text-white' : 'text-neutral-400 dark:text-neutral-500'}`}>
                {item.label}
              </div>
              <div className="flex items-baseline gap-2">
                <span className="text-xl sm:text-2xl font-bold text-neutral-900 dark:text-white">
                  {item.value}
                </span>
                <TrendBadge trend={item.trend} invert={item.invertTrend} />
              </div>
              <p className="text-[11px] text-neutral-400 dark:text-neutral-500 mt-0.5">{trendContext}</p>
              {isActive && (
                <div className="absolute bottom-0 left-0 right-0 h-[3px] bg-brand-orange" />
              )}
            </button>
          )
        })}
      </div>

      {/* Chart Area */}
      <div className="px-4 sm:px-6 pt-4 pb-2">
        {/* Toolbar */}
        <div className="flex items-center justify-between gap-3 mb-4">
          {/* Left: metric label + avg badge */}
          <div className="flex items-center gap-3">
            <span className="text-xs font-medium text-neutral-500 dark:text-neutral-400">
              {metricLabel}
            </span>
            {hasPrev && (
              <div className="hidden sm:flex items-center gap-3 text-[11px] font-medium text-neutral-400 dark:text-neutral-500 ml-2">
                <span className="flex items-center gap-1.5">
                  <span className="h-1.5 w-1.5 rounded-full bg-brand-orange" />
                  Current
                </span>
                <span className="flex items-center gap-1.5">
                  <span className="h-1.5 w-1.5 rounded-full border border-dashed" style={{ borderColor: colors.axis }} />
                  Previous{prevPeriodLabel ? ` (${prevPeriodLabel})` : ''}
                </span>
              </div>
            )}
          </div>

          {/* Right: controls */}
          <div className="flex items-center gap-2">
            {dateRange.start === dateRange.end ? (
              <Select
                value={todayInterval}
                onChange={(value) => setTodayInterval(value as 'minute' | 'hour')}
                options={[
                  { value: 'minute', label: '1 min' },
                  { value: 'hour', label: '1 hour' },
                ]}
                className="min-w-[90px]"
              />
            ) : (
              <Select
                value={multiDayInterval}
                onChange={(value) => setMultiDayInterval(value as 'hour' | 'day')}
                options={[
                  { value: 'hour', label: '1 hour' },
                  { value: 'day', label: '1 day' },
                ]}
                className="min-w-[90px]"
              />
            )}

            {prevData?.length ? (
              <Checkbox
                checked={showComparison}
                onCheckedChange={setShowComparison}
                label="Compare"
              />
            ) : null}

            <button
              onClick={handleExportChart}
              disabled={!hasData}
              className="p-1.5 text-neutral-400 dark:text-neutral-500 hover:text-neutral-600 dark:hover:text-neutral-300 transition-colors disabled:opacity-30 cursor-pointer"
              title="Export chart as PNG"
            >
              <DownloadIcon className="w-4 h-4" />
            </button>
          </div>
        </div>

        {!hasData ? (
          <div className="flex h-72 flex-col items-center justify-center gap-2">
            <BarChartIcon className="h-10 w-10 text-neutral-200 dark:text-neutral-700" aria-hidden />
            <p className="text-sm text-neutral-400 dark:text-neutral-500">No data for this period</p>
          </div>
        ) : !hasAnyNonZero ? (
          <div className="flex h-72 flex-col items-center justify-center gap-2">
            <BarChartIcon className="h-10 w-10 text-neutral-200 dark:text-neutral-700" aria-hidden />
            <p className="text-sm text-neutral-400 dark:text-neutral-500">No {metricLabel.toLowerCase()} recorded</p>
          </div>
        ) : (
          <div className="h-[320px] w-full">
            <ResponsiveContainer width="100%" height="100%">
              <AreaChart data={chartData} margin={{ top: 8, right: 8, left: 0, bottom: 8 }}>
                <defs>
                  <linearGradient id={`gradient-${metric}`} x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stopColor={COLORS.brand} stopOpacity={0.25} />
                    <stop offset="100%" stopColor={COLORS.brand} stopOpacity={0} />
                  </linearGradient>
                </defs>
                <CartesianGrid
                  strokeDasharray="3 3"
                  vertical={false}
                  stroke={colors.grid}
                />
                <XAxis
                  dataKey="date"
                  stroke={colors.axis}
                  fontSize={11}
                  tickLine={false}
                  axisLine={false}
                  minTickGap={40}
                  ticks={midnightTicks ?? dayTicks}
                  dy={8}
                />
                <YAxis
                  stroke={colors.axis}
                  fontSize={11}
                  tickLine={false}
                  axisLine={false}
                  domain={[0, 'auto']}
                  width={40}
                  allowDecimals={!isCountMetric}
                  tickFormatter={(val) => {
                    if (metric === 'bounce_rate') return `${val}%`
                    if (metric === 'avg_duration') return formatAxisDuration(val)
                    return formatAxisValue(val)
                  }}
                />
                <Tooltip
                  content={(p: TooltipProps<number, string>) => (
                    <ChartTooltip
                      active={p.active}
                      payload={p.payload as Array<{ payload: Record<string, number>; value: number; dataKey?: string }>}
                      label={p.label as string}
                      metric={metric}
                      metricLabel={metricLabel}
                      formatNumberFn={formatNumber}
                      showComparison={hasPrev}
                      prevPeriodLabel={prevPeriodLabel}
                      colors={colors}
                    />
                  )}
                  cursor={{ stroke: colors.axis, strokeOpacity: 0.3, strokeWidth: 1 }}
                />


                {hasPrev && (
                  <Area
                    type="monotone"
                    dataKey={metric === 'visitors' ? 'prevVisitors' : metric === 'pageviews' ? 'prevPageviews' : metric === 'bounce_rate' ? 'prevBounceRate' : 'prevAvgDuration'}
                    stroke={colors.axis}
                    strokeWidth={1.5}
                    strokeDasharray="4 4"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    fill="none"
                    dot={false}
                    isAnimationActive
                    animationDuration={400}
                    animationEasing="ease-out"
                  />
                )}

                <Area
                  type="monotone"
                  baseValue={0}
                  dataKey={metric}
                  stroke={COLORS.brand}
                  strokeWidth={2}
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  fillOpacity={1}
                  fill={`url(#gradient-${metric})`}
                  dot={false}
                  activeDot={{
                    r: 4,
                    strokeWidth: 2,
                    fill: resolvedTheme === 'dark' ? 'var(--color-neutral-900)' : '#ffffff',
                    stroke: COLORS.brand,
                  }}
                  isAnimationActive
                  animationDuration={400}
                  animationEasing="ease-out"
                />
              </AreaChart>
            </ResponsiveContainer>
          </div>
        )}
      </div>

      {/* Live indicator */}
      {lastUpdatedAt != null && (
        <div className="px-4 sm:px-6 pb-3 flex justify-end">
          <div className="flex items-center gap-1.5 text-[11px] text-neutral-400 dark:text-neutral-500">
            <span className="relative flex h-1.5 w-1.5">
              <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-500 opacity-75" />
              <span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-green-500" />
            </span>
            Live · {formatUpdatedAgo(lastUpdatedAt)}
          </div>
        </div>
      )}
    </div>
  )
}
