import { useMemo } from 'react'
import { useQuery } from '@tanstack/react-query'
import ReactEChartsCore from 'echarts-for-react/lib/core'
import * as echarts from 'echarts/core'
import { PieChart } from 'echarts/charts'
import { LegendComponent, TooltipComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'

import type {
  DateRangeValue,
  ToolChartOption,
  UsageToolBreakdownQueryInput,
  UsageToolBreakdownResponse,
} from './types'
import { fetchUsageToolBreakdown } from './api'
import { getSharedToolMetadata, USAGE_SKIP_TOOL_NAMES } from '../tooling/toolMetadata'
import type { TopLevelFormatterParams } from 'echarts/types/dist/shared'

echarts.use([PieChart, LegendComponent, TooltipComponent, CanvasRenderer])

const toolPalette = [
  '#2563eb',
  '#f97316',
  '#10b981',
  '#a855f7',
  '#facc15',
  '#ef4444',
  '#0ea5e9',
  '#22c55e',
  '#ec4899',
  '#6366f1',
]

type ChartSegment = {
  key: string
  label: string
  value: number
  invocations: number
}

type UsageToolChartProps = {
  effectiveRange: DateRangeValue | null
  fallbackRange: DateRangeValue | null
  agentIds: string[]
  timezone?: string
  embedded?: boolean
}

export function UsageToolChart({ effectiveRange, fallbackRange, agentIds, timezone, embedded = false }: UsageToolChartProps) {
  const baseRange = effectiveRange ?? fallbackRange

  const creditFormatter = useMemo(
    () => new Intl.NumberFormat(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 3 }),
    [],
  )

  const queryInput = useMemo<UsageToolBreakdownQueryInput | null>(() => {
    if (!baseRange) {
      return null
    }
    return {
      from: baseRange.start.toString(),
      to: baseRange.end.toString(),
      agents: agentIds,
    }
  }, [agentIds, baseRange])

  const agentKey = agentIds.length ? agentIds.slice().sort().join(',') : 'all'

  const {
    data: toolData,
    error: toolError,
    isError,
    isPending,
  } = useQuery<UsageToolBreakdownResponse, Error>({
    queryKey: ['usage-tool-breakdown', queryInput?.from ?? null, queryInput?.to ?? null, agentKey],
    queryFn: ({ signal }) => fetchUsageToolBreakdown(queryInput!, signal),
    enabled: Boolean(queryInput),
    refetchOnWindowFocus: false,
    placeholderData: (previous) => previous,
  })

  const processedSegments = useMemo<ChartSegment[]>(() => {
    if (!toolData) {
      return []
    }

    const segments = new Map<string, ChartSegment>()
    let otherCredits = 0
    let otherInvocations = 0

    for (const entry of toolData.tools) {
      if (!entry) {
        continue
      }

      const rawName = entry.name ?? ''
      const normalized = rawName.toLowerCase()
      const metadata = getSharedToolMetadata(rawName)
      const shouldSkip = USAGE_SKIP_TOOL_NAMES.has(normalized) || metadata.skip

      const rawInvocations = Number(entry.invocations ?? 0)
      const invocations = Number.isFinite(rawInvocations) && rawInvocations > 0 ? rawInvocations : 0
      const rawCredits = typeof entry.credits === 'number' ? entry.credits : Number(entry.credits ?? 0)
      const credits = Number.isFinite(rawCredits) && rawCredits > 0 ? rawCredits : 0

      if (invocations <= 0 && credits <= 0) {
        continue
      }

      if (shouldSkip) {
        otherInvocations += invocations
        otherCredits += credits
        continue
      }

      const key = metadata.name || rawName || 'default'
      const label = metadata.label || (rawName ? rawName.replaceAll('_', ' ') : 'Other')
      const existing = segments.get(key)
      if (existing) {
        existing.value += credits
        existing.invocations += invocations
      } else {
        segments.set(key, { key, label, value: credits, invocations })
      }
    }

    if (otherCredits > 0) {
      const existingOther = segments.get('other')
      if (existingOther) {
        existingOther.value += otherCredits
        existingOther.invocations += otherInvocations
      } else {
        segments.set('other', { key: 'other', label: 'Other', value: otherCredits, invocations: otherInvocations })
      }
    }

    return Array.from(segments.values()).sort((a, b) => {
      if (b.value === a.value) {
        return b.invocations - a.invocations
      }
      return b.value - a.value
    })
  }, [toolData])

  const chartOption = useMemo<ToolChartOption | null>(() => {
    if (!processedSegments.length) {
      return null
    }

    const data = processedSegments.map((segment, index) => ({
      value: segment.value,
      name: segment.label,
      invocations: segment.invocations,
      itemStyle: {
        color: toolPalette[index % toolPalette.length],
      },
    }))

    return {
      textStyle: {
        color: embedded ? '#cbd5e1' : '#334155',
      },
      tooltip: {
        trigger: 'item',
        backgroundColor: embedded ? 'rgba(15, 23, 42, 0.96)' : undefined,
        borderColor: embedded ? 'rgba(148, 163, 184, 0.25)' : undefined,
        textStyle: embedded ? { color: '#f8fafc' } : undefined,
        formatter: (params: TopLevelFormatterParams) => {
          const detail = Array.isArray(params) ? params[0] : params
          if (!detail) {
            return ''
          }

          const { name, value: rawCredits, percent: rawPercent } = detail

          const credits = typeof rawCredits === 'number' ? rawCredits : Number(rawCredits ?? 0)
          const percentValue =
            typeof rawPercent === 'number' ? rawPercent : Number(rawPercent ?? 0)

          const safeCredits = Number.isFinite(credits) ? credits : 0
          const safePercent = Number.isFinite(percentValue) ? percentValue : 0

          const label =
            typeof name === 'string' && name.length
              ? name
              : name != null
              ? String(name)
              : 'Tool'

          const formattedCredits = creditFormatter.format(safeCredits)

          return `${label}<br />${formattedCredits} credits (${safePercent.toFixed(1)}%)`
        },
      },
      legend: {
        type: 'scroll',
        orient: 'vertical',
        right: 0,
        top: 'middle',
        align: 'left',
        textStyle: {
          color: embedded ? '#cbd5e1' : '#334155',
        },
      },
      series: [
        {
          name: 'Tool credits',
          type: 'pie',
          radius: ['40%', '70%'],
          center: ['40%', '50%'],
          avoidLabelOverlap: false,
          itemStyle: {
            borderRadius: 6,
            borderColor: embedded ? '#0f172a' : '#fff',
            borderWidth: 1,
          },
          label: {
            show: true,
            formatter: '{b}: {d}%',
            color: embedded ? '#cbd5e1' : '#334155',
          },
          labelLine: {
            show: true,
          },
          data,
        },
      ],
    }
  }, [embedded, processedSegments, creditFormatter])

  const isLoading = Boolean(queryInput) && isPending

  const errorMessage = useMemo(() => {
    if (!isError) {
      return null
    }
    if (toolError instanceof Error) {
      return toolError.message
    }
    return 'Unable to load tool usage right now.'
  }, [isError, toolError])

  const emptyMessage = baseRange
    ? 'No billable tool usage recorded for this window.'
    : 'Select a billing period to view tool usage.'

  const summaryRange = useMemo(() => {
    if (!toolData) {
      return null
    }
    const tz = toolData.timezone || timezone
    const formatter = new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeZone: tz })
    const start = formatter.format(new Date(toolData.range.start))
    const end = formatter.format(new Date(toolData.range.end))
    return start === end ? start : `${start} – ${end}`
  }, [timezone, toolData])

  const totalCredits = toolData?.total_credits ?? processedSegments.reduce((acc, segment) => acc + segment.value, 0)
  const sectionClassName = embedded
    ? 'flex flex-col gap-4 rounded-xl border border-slate-200/20 bg-slate-950/35 p-6'
    : 'gobii-card-base flex flex-col gap-4 p-6'
  const titleClassName = embedded ? 'text-lg font-semibold text-slate-50' : 'text-lg font-semibold text-slate-900'
  const subtitleClassName = embedded ? 'text-sm text-slate-400' : 'text-sm text-slate-500'
  const totalClassName = embedded
    ? 'rounded-md border border-slate-200/20 bg-slate-900/45 px-3 py-1 text-sm text-slate-300'
    : 'rounded-md border border-white/60 bg-white/60 px-3 py-1 text-sm text-slate-600'
  const totalValueClassName = embedded ? 'font-medium text-slate-50' : 'font-medium text-slate-900'
  const loadingClassName = 'flex h-full items-center justify-center text-sm text-slate-400'
  const errorClassName = embedded
    ? 'flex h-full items-center justify-center text-sm text-rose-300'
    : 'flex h-full items-center justify-center text-sm text-red-600'
  const emptyClassName = embedded ? 'text-slate-400' : 'text-slate-400'

  return (
    <section className={sectionClassName}>
      <div className="flex flex-wrap items-center justify-between gap-3">
        <div>
          <h2 className={titleClassName}>Tool credit breakdown</h2>
          <p className={subtitleClassName}>
            Credits billed by tool{summaryRange ? ` · ${summaryRange}` : ''}
          </p>
        </div>
        {toolData ? (
          <div className={totalClassName}>
            <span className={totalValueClassName}>{creditFormatter.format(totalCredits)}</span> credits
          </div>
        ) : null}
      </div>
      <div className="h-80 w-full">
        {isLoading ? (
          <div className={loadingClassName}>Loading tool usage…</div>
        ) : isError && errorMessage ? (
          <div className={errorClassName}>{errorMessage}</div>
        ) : chartOption ? (
          <div className="flex h-full flex-col">
            <div className="flex-1">
              <ReactEChartsCore echarts={echarts} option={chartOption} notMerge lazyUpdate style={{ height: '100%', width: '100%' }} />
            </div>
            {processedSegments.length === 0 ? (
              <div className={`mt-2 text-center text-xs ${emptyClassName}`}>{emptyMessage}</div>
            ) : null}
          </div>
        ) : (
          <div className={loadingClassName}>{emptyMessage}</div>
        )}
      </div>
    </section>
  )
}

export type { UsageToolChartProps }
