import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ArrowsClockwiseIcon } from '@phosphor-icons/react'
import {
  Alert,
  Button,
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  LoadingBlock,
  QueryErrorState,
} from '@/ui'
import { useWebhookStats } from '@/api/queries'
import type { WebhookStatsBucket } from '@/api/client'
import { cn } from '@/lib/utils'

/**
 * Time-series histogram delivery'и подписки. Stacked bar chart на чистом SVG
 * (без recharts/chart-js dependency'и — bundle stays slim).
 *
 * <p>Layout:
 * <pre>
 *   ┌────────────────────────────────────────────────────────┐
 *   │ Header: title + bucketBy toggle (hour/day) + refresh   │
 *   ├────────────────────────────────────────────────────────┤
 *   │ Legend: pending · retrying · delivered · dlq           │
 *   ├────────────────────────────────────────────────────────┤
 *   │ Chart area:                                            │
 *   │   stacked bars per bucket, y-axis = count              │
 *   │   x-axis ticks: каждый 4-й bucket (hour) / day name    │
 *   │   hover tooltip → counts breakdown                     │
 *   └────────────────────────────────────────────────────────┘
 * </pre>
 *
 * <p>Empty state: «Нет данных за выбранный период» — когда все buckets total=0.
 * Visible-only: фильтруем chart area до bucket'ов, где total > 0, чтобы
 * sparse data не растягивала ось. X-axis labels всё равно показывают полный
 * диапазон чтобы юзер видел временное окно.
 */
export function WebhookStatsHistogram({
  subscriptionId,
}: {
  subscriptionId: string
}) {
  const { t } = useTranslation()
  const [bucketBy, setBucketBy] = useState<'hour' | 'day'>('hour')

  const stats = useWebhookStats(subscriptionId, bucketBy)

  if (stats.isLoading) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{t('webhooks.histogram.title')}</CardTitle>
        </CardHeader>
        <CardContent>
          <LoadingBlock />
        </CardContent>
      </Card>
    )
  }

  if (stats.isError) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{t('webhooks.histogram.title')}</CardTitle>
        </CardHeader>
        <CardContent>
          <QueryErrorState error={stats.error} onRetry={() => stats.refetch()} />
        </CardContent>
      </Card>
    )
  }

  const data = stats.data
  if (!data) return null

  return (
    <Card>
      <CardHeader className="flex flex-row items-center justify-between gap-3">
        <CardTitle>{t('webhooks.histogram.title')}</CardTitle>
        <div className="flex items-center gap-2">
          <div className="inline-flex rounded-md border border-line overflow-hidden text-cap">
            <button
              type="button"
              onClick={() => setBucketBy('hour')}
              className={cn(
                'px-2.5 py-1 transition-colors',
                bucketBy === 'hour'
                  ? 'bg-accent text-on-accent'
                  : 'bg-surface text-ink-2 hover:bg-surface-2',
              )}
            >
              {t('webhooks.histogram.bucket.hour', { defaultValue: '24ч' })}
            </button>
            <button
              type="button"
              onClick={() => setBucketBy('day')}
              className={cn(
                'px-2.5 py-1 transition-colors border-l border-line',
                bucketBy === 'day'
                  ? 'bg-accent text-on-accent'
                  : 'bg-surface text-ink-2 hover:bg-surface-2',
              )}
            >
              {t('webhooks.histogram.bucket.day', { defaultValue: '7д' })}
            </button>
          </div>
          <Button
            variant="ghost"
            size="sm"
            onClick={() => stats.refetch()}
            disabled={stats.isFetching}
            aria-label={t('common.refresh')}
            title={t('common.refresh')}
          >
            <ArrowsClockwiseIcon
              size={14}
              weight="regular"
              className={stats.isFetching ? 'animate-spin' : undefined}
            />
          </Button>
        </div>
      </CardHeader>
      <CardContent>
        <HistogramChart buckets={data.buckets} bucketBy={data.bucketBy} />
      </CardContent>
    </Card>
  )
}

const STATUS_TOKENS = {
  delivered: { color: 'fill-jade', labelKey: 'webhooks.status.delivered' },
  retrying: { color: 'fill-amber', labelKey: 'webhooks.status.retrying' },
  pending: { color: 'fill-mute/60', labelKey: 'webhooks.status.pending' },
  dlq: { color: 'fill-mars', labelKey: 'webhooks.status.dlq' },
} as const

type StatusKey = keyof typeof STATUS_TOKENS

const STACK_ORDER: StatusKey[] = ['delivered', 'retrying', 'pending', 'dlq']

const CHART_HEIGHT = 180
const CHART_PADDING = { top: 8, right: 8, bottom: 28, left: 32 }

function HistogramChart({
  buckets,
  bucketBy,
}: {
  buckets: WebhookStatsBucket[]
  bucketBy: 'hour' | 'day'
}) {
  const { t, i18n } = useTranslation()
  const [hoveredIdx, setHoveredIdx] = useState<number | null>(null)

  const maxTotal = useMemo(
    () => Math.max(1, ...buckets.map((b) => b.total)),
    [buckets],
  )

  // Если всё пусто — показываем empty state, не пустой chart с одним пикселем.
  if (buckets.every((b) => b.total === 0)) {
    return (
      <Alert variant="info" className="mt-2">
        {t('webhooks.histogram.empty', {
          defaultValue: 'Нет доставок за выбранный период.',
        })}
      </Alert>
    )
  }

  const innerHeight = CHART_HEIGHT - CHART_PADDING.top - CHART_PADDING.bottom
  const bucketCount = buckets.length

  // ViewBox единиц: используем pixel-like coords чтобы text/тики читались.
  // SVG растягивается через preserveAspectRatio (none) на full container width.
  const VB_W = 800
  const VB_H = CHART_HEIGHT
  const innerW = VB_W - CHART_PADDING.left - CHART_PADDING.right
  const barW = innerW / bucketCount
  const barGap = Math.max(1, Math.min(2, barW * 0.15))
  const actualBarW = Math.max(1, barW - barGap)

  const tickStep = bucketBy === 'hour'
    ? Math.max(1, Math.floor(bucketCount / 6)) // 4 ticks per 24h
    : 1 // каждый день для 7d view

  return (
    <div className="space-y-2">
      <Legend />
      <div className="relative">
        <svg
          viewBox={`0 0 ${VB_W} ${VB_H}`}
          preserveAspectRatio="none"
          className="w-full h-44"
          role="img"
          aria-label={t('webhooks.histogram.title')}
        >
          {/* Y-axis ticks (0, mid, max) */}
          <g className="text-mute" fontSize="10" fontFamily="ui-monospace, monospace">
            {[0, 0.5, 1].map((frac) => {
              const y = CHART_PADDING.top + innerHeight * (1 - frac)
              const val = Math.round(maxTotal * frac)
              return (
                <g key={frac}>
                  <line
                    x1={CHART_PADDING.left}
                    x2={VB_W - CHART_PADDING.right}
                    y1={y}
                    y2={y}
                    stroke="currentColor"
                    strokeOpacity={frac === 0 ? 0.4 : 0.15}
                    strokeWidth={1}
                  />
                  <text
                    x={CHART_PADDING.left - 4}
                    y={y + 3}
                    textAnchor="end"
                    fill="currentColor"
                  >
                    {val}
                  </text>
                </g>
              )
            })}
          </g>

          {/* Stacked bars */}
          {buckets.map((bucket, idx) => {
            const x = CHART_PADDING.left + idx * barW + barGap / 2
            let yCursor = CHART_PADDING.top + innerHeight
            const isHovered = hoveredIdx === idx
            return (
              <g
                key={bucket.ts}
                onMouseEnter={() => setHoveredIdx(idx)}
                onMouseLeave={() => setHoveredIdx(null)}
                className="cursor-pointer"
              >
                {/* Невидимая hover-zone — full column. Чтобы hover работал
                  * даже на zero bucket'ах. */}
                <rect
                  x={x - barGap / 2}
                  y={CHART_PADDING.top}
                  width={barW}
                  height={innerHeight}
                  fill="transparent"
                />
                {STACK_ORDER.map((status) => {
                  const value = bucket[status]
                  if (!value) return null
                  const segH = (value / maxTotal) * innerHeight
                  yCursor -= segH
                  return (
                    <rect
                      key={status}
                      x={x}
                      y={yCursor}
                      width={actualBarW}
                      height={segH}
                      className={cn(
                        STATUS_TOKENS[status].color,
                        'transition-opacity',
                        isHovered ? 'opacity-100' : 'opacity-85',
                      )}
                    />
                  )
                })}
              </g>
            )
          })}

          {/* X-axis ticks */}
          <g className="text-mute" fontSize="10" fontFamily="ui-monospace, monospace">
            {buckets.map((bucket, idx) => {
              if (idx % tickStep !== 0 && idx !== buckets.length - 1) return null
              const x = CHART_PADDING.left + idx * barW + barW / 2
              return (
                <text
                  key={bucket.ts}
                  x={x}
                  y={VB_H - 10}
                  textAnchor="middle"
                  fill="currentColor"
                >
                  {formatTick(bucket.ts, bucketBy, i18n.language)}
                </text>
              )
            })}
          </g>
        </svg>

        {/* Tooltip overlay */}
        {hoveredIdx !== null && (
          <BucketTooltip
            bucket={buckets[hoveredIdx]}
            bucketBy={bucketBy}
            locale={i18n.language}
            // Position: справа от hovered bar если в первой половине, иначе слева
            position={hoveredIdx < buckets.length / 2 ? 'right' : 'left'}
          />
        )}
      </div>
    </div>
  )
}

function Legend() {
  const { t } = useTranslation()
  return (
    <div className="flex flex-wrap items-center gap-3 text-cap text-mute">
      {STACK_ORDER.map((status) => (
        <div key={status} className="inline-flex items-center gap-1.5">
          <svg width={10} height={10} className="shrink-0">
            <rect
              x={0}
              y={0}
              width={10}
              height={10}
              className={STATUS_TOKENS[status].color}
              rx={2}
            />
          </svg>
          <span>{t(STATUS_TOKENS[status].labelKey)}</span>
        </div>
      ))}
    </div>
  )
}

function BucketTooltip({
  bucket,
  bucketBy,
  locale,
  position,
}: {
  bucket: WebhookStatsBucket
  bucketBy: 'hour' | 'day'
  locale: string
  position: 'left' | 'right'
}) {
  const { t } = useTranslation()
  return (
    <div
      className={cn(
        'pointer-events-none absolute top-1 z-10 rounded-md border border-line bg-surface-2 px-3 py-2 shadow-lg text-cap',
        position === 'right' ? 'left-2' : 'right-2',
      )}
    >
      <div className="text-mono text-ink-2 font-semibold mb-1">
        {formatTooltip(bucket.ts, bucketBy, locale)}
      </div>
      <div className="space-y-0.5">
        {STACK_ORDER.map((status) => {
          const value = bucket[status]
          if (!value) return null
          return (
            <div key={status} className="flex items-center gap-2">
              <svg width={8} height={8} className="shrink-0">
                <rect
                  x={0}
                  y={0}
                  width={8}
                  height={8}
                  className={STATUS_TOKENS[status].color}
                  rx={2}
                />
              </svg>
              <span className="text-ink-2">{t(STATUS_TOKENS[status].labelKey)}</span>
              <span className="text-mono text-ink ml-auto">{value}</span>
            </div>
          )
        })}
        <div className="border-t border-line mt-1 pt-1 flex items-center justify-between text-mute">
          <span>{t('webhooks.histogram.total', { defaultValue: 'итого' })}</span>
          <span className="text-mono text-ink">{bucket.total}</span>
        </div>
      </div>
    </div>
  )
}

const formatTick = (iso: string, bucketBy: 'hour' | 'day', locale: string): string => {
  const d = new Date(iso)
  if (bucketBy === 'hour') {
    return d.toLocaleTimeString(locale === 'ru' ? 'ru-RU' : 'en-US', {
      hour: '2-digit',
      minute: '2-digit',
    })
  }
  return d.toLocaleDateString(locale === 'ru' ? 'ru-RU' : 'en-US', {
    day: '2-digit',
    month: '2-digit',
  })
}

const formatTooltip = (iso: string, bucketBy: 'hour' | 'day', locale: string): string => {
  const d = new Date(iso)
  if (bucketBy === 'hour') {
    return d.toLocaleString(locale === 'ru' ? 'ru-RU' : 'en-US', {
      day: '2-digit',
      month: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
    })
  }
  return d.toLocaleDateString(locale === 'ru' ? 'ru-RU' : 'en-US', {
    day: '2-digit',
    month: 'long',
    year: 'numeric',
  })
}
