import { Fragment, useCallback, useEffect, useState } from 'react'
import { accountQuota, usageStats, usageTrend } from '../ipc'
import type { AccountQuota, Subscription, UsageBucket, UsageStats } from '../types'
import { Modal } from './Modal'
import { IconRefresh } from './Icons'

/** token 数量紧凑格式化：1.2k / 3.4M */
function fmt(n: number): string {
  if (n < 1000) return String(n)
  if (n < 1_000_000) return `${(n / 1000).toFixed(1)}k`
  return `${(n / 1_000_000).toFixed(1)}M`
}

function bucketTitle(b: UsageBucket): string {
  const parts = [
    `输入 ${b.inputTokens.toLocaleString()}`,
    `输出 ${b.outputTokens.toLocaleString()}`,
    `缓存读 ${b.cacheReadTokens.toLocaleString()}`,
    `缓存写 ${b.cacheCreationTokens.toLocaleString()}`
  ]
  if (b.costUsd > 0) parts.push(`$${b.costUsd.toFixed(2)}`)
  return parts.join(' · ')
}

/** 本地时区的 今日/本周(周一起)/本月 起点 */
function windowStarts(): [number, number, number] {
  const now = new Date()
  const dayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime()
  const mondayOffset = (now.getDay() + 6) % 7
  const weekStart = dayStart - mondayOffset * 86_400_000
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).getTime()
  return [dayStart, weekStart, monthStart]
}

const TIER_LABEL: Record<string, string> = {
  five_hour: '5 小时',
  seven_day: '本周',
  seven_day_opus: '周 Opus'
}

/** 始终隐藏的窗口（即便有用量） */
const HIDDEN_TIERS = new Set(['seven_day_sonnet'])

/** 在行下额外显示「下次刷新」时间的窗口 */
const SHOW_RESET = new Set(['five_hour', 'seven_day'])

function resetText(iso: string | null): string {
  if (!iso) return ''
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return ''
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())} 重置`
}

/** 下次刷新时间：MM-DD HH:MM（不带「重置」后缀，用于行下小字） */
function refreshText(iso: string | null): string {
  if (!iso) return ''
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return ''
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

/** ISO 日期格式化为 YYYY-MM-DD */
function dateText(iso: string | null): string {
  if (!iso) return ''
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return ''
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`
}

const SUB_STATUS_LABEL: Record<string, string> = {
  active: '活跃',
  trialing: '试用中',
  canceled: '已取消',
  past_due: '逾期',
  paused: '已暂停'
}

/** 套餐标签：套餐名 + 速率倍率（从 default_claude_max_20x 提取 20x） */
function planLabel(sub: Subscription): string {
  const mult = sub.tier?.match(/(\d+x)\b/)?.[1]
  return mult ? `${sub.plan} ${mult}` : sub.plan
}

/** 日期行：试用期显示试用到期，否则显示订阅开始日（官方无活跃订阅到期日） */
function subDateLine(sub: Subscription): string {
  if (sub.trialEndsAt) {
    const t = dateText(sub.trialEndsAt)
    if (t) return `试用至 ${t}`
  }
  const s = dateText(sub.startedAt)
  return s ? `订阅于 ${s}` : ''
}

/** 利用率配色：<60% 正常，60-85% 警告，>85% 危险 */
function utilColor(utilization: number): string {
  if (utilization >= 85) return 'var(--danger)'
  if (utilization >= 60) return 'var(--warn)'
  return 'var(--accent)'
}

const QUOTA_STATUS_TEXT: Record<string, string> = {
  no_credentials: '未登录',
  expired: '凭据过期',
  error: '查询失败'
}

/**
 * 侧边栏用量区块，两部分：
 * 1. 账号额度：经 OAuth 凭据查询官方订阅配额（5 小时窗口 / 周限额等，与 CLI /usage 同源）
 * 2. 本机统计：聚合 ~/.claude/projects 全部会话记录的 token 用量
 */
export function UsagePanel() {
  const [stats, setStats] = useState<UsageStats | null>(null)
  const [quota, setQuota] = useState<AccountQuota | null>(null)
  const [loading, setLoading] = useState(false)
  const [trendOpen, setTrendOpen] = useState(false)

  const refresh = useCallback(async () => {
    setLoading(true)
    try {
      const [d, w, m] = windowStarts()
      const [statsResult, quotaResult] = await Promise.all([usageStats(d, w, m), accountQuota()])
      setStats(statsResult)
      setQuota(quotaResult)
    } finally {
      setLoading(false)
    }
  }, [])

  // 挂载时加载，之后每 5 分钟自动刷新
  useEffect(() => {
    void refresh()
    const timer = setInterval(() => void refresh(), 5 * 60_000)
    return () => clearInterval(timer)
  }, [refresh])

  const rows: { label: string; bucket: UsageBucket | undefined }[] = [
    { label: '今日', bucket: stats?.day },
    { label: '本周', bucket: stats?.week },
    { label: '本月', bucket: stats?.month }
  ]

  return (
    <div className="usage-panel">
      <div className="usage-header">
        <span>账号额度</span>
        <button
          className="btn ghost small"
          title="刷新"
          disabled={loading}
          onClick={() => void refresh()}
        >
          <IconRefresh width={11} height={11} />
        </button>
      </div>
      {!quota && <div className="usage-hint">查询中…</div>}
      {quota && quota.status !== 'ok' && (
        <div className="usage-hint" title={quota.message ?? ''}>
          {QUOTA_STATUS_TEXT[quota.status] ?? quota.status}
          {quota.message ? `：${quota.message}` : ''}
        </div>
      )}
      {quota?.status === 'ok' && quota.subscription && (
        <div className="usage-sub" title="官方接口不提供活跃订阅的到期日，此处显示订阅开始日">
          <span className="usage-sub-plan">{planLabel(quota.subscription)}</span>
          {SUB_STATUS_LABEL[quota.subscription.status] && (
            <span className="usage-sub-status">
              {SUB_STATUS_LABEL[quota.subscription.status]}
            </span>
          )}
          {subDateLine(quota.subscription) && (
            <span className="usage-sub-date">{subDateLine(quota.subscription)}</span>
          )}
        </div>
      )}
      {quota?.status === 'ok' &&
        quota.tiers
          // 隐藏指定窗口；已知窗口始终显示；实验性未知窗口只在有用量时显示，避免刷屏
          .filter(
            (t) =>
              !HIDDEN_TIERS.has(t.name) &&
              (TIER_LABEL[t.name] !== undefined || t.utilization > 0)
          )
          .map((tier) => (
            <Fragment key={tier.name}>
              <div
                className="quota-row"
                title={`已用 ${tier.utilization.toFixed(1)}%${tier.resetsAt ? ` · ${resetText(tier.resetsAt)}` : ''}`}
              >
                <span className="usage-label">{TIER_LABEL[tier.name] ?? tier.name}</span>
                <span className="quota-pct" style={{ color: utilColor(tier.utilization) }}>
                  {Math.round(tier.utilization)}%
                </span>
              </div>
              {SHOW_RESET.has(tier.name) && tier.resetsAt && (
                <div className="quota-reset">下次刷新 {refreshText(tier.resetsAt)}</div>
              )}
            </Fragment>
          ))}
      {quota?.status === 'ok' && quota.extraUsage?.isEnabled && (
        <div
          className="usage-hint"
          title={`超额已用 ${quota.extraUsage.usedCredits ?? 0} / 上限 ${quota.extraUsage.monthlyLimit ?? '-'} ${quota.extraUsage.currency ?? ''}`}
        >
          超额用量已启用
          {quota.extraUsage.utilization != null ? ` · ${Math.round(quota.extraUsage.utilization)}%` : ''}
        </div>
      )}

      <div className="usage-header" style={{ marginTop: 6 }}>
        <span>本机统计（tokens）</span>
        <button className="btn ghost small" title="近 30 天趋势" onClick={() => setTrendOpen(true)}>
          趋势
        </button>
      </div>
      {rows.map(({ label, bucket }) => (
        <div key={label} className="usage-row" title={bucket ? bucketTitle(bucket) : ''}>
          <span className="usage-label">{label}</span>
          {bucket ? (
            <span className="usage-value">
              入 {fmt(bucket.inputTokens + bucket.cacheCreationTokens)} · 出 {fmt(bucket.outputTokens)}
            </span>
          ) : (
            <span className="usage-value">…</span>
          )}
        </div>
      ))}

      {trendOpen && <TrendDialog onClose={() => setTrendOpen(false)} />}
    </div>
  )
}

const TREND_DAYS = 30

/** 近 30 天逐日用量柱状图：上段输出、下段输入（含缓存写） */
function TrendDialog({ onClose }: { onClose: () => void }) {
  const [trend, setTrend] = useState<UsageBucket[] | null>(null)

  useEffect(() => {
    const [todayStart] = windowStarts()
    void usageTrend(todayStart, TREND_DAYS).then(setTrend)
  }, [])

  const dayLabel = (offset: number): string => {
    const d = new Date(Date.now() - (TREND_DAYS - 1 - offset) * 86_400_000)
    return `${d.getMonth() + 1}/${d.getDate()}`
  }

  const max = trend
    ? Math.max(1, ...trend.map((b) => b.inputTokens + b.cacheCreationTokens + b.outputTokens))
    : 1

  return (
    <Modal
      title={`近 ${TREND_DAYS} 天用量趋势`}
      width={680}
      onClose={onClose}
      footer={<button className="btn" onClick={onClose}>关闭</button>}
    >
      {!trend && <div className="empty-hint">统计中…</div>}
      {trend && (
        <>
          <div className="trend-chart">
            {trend.map((b, i) => {
              const input = b.inputTokens + b.cacheCreationTokens
              return (
                <div
                  key={i}
                  className="trend-col"
                  title={`${dayLabel(i)}：入 ${fmt(input)} · 出 ${fmt(b.outputTokens)} · 缓存读 ${fmt(b.cacheReadTokens)}${b.costUsd > 0 ? ` · $${b.costUsd.toFixed(2)}` : ''}`}
                >
                  <div className="trend-bar">
                    <div
                      className="trend-seg output"
                      style={{ height: `${(b.outputTokens / max) * 100}%` }}
                    />
                    <div className="trend-seg input" style={{ height: `${(input / max) * 100}%` }} />
                  </div>
                  {i % 7 === (TREND_DAYS - 1) % 7 ? (
                    <div className="trend-label">{dayLabel(i)}</div>
                  ) : (
                    <div className="trend-label" />
                  )}
                </div>
              )
            })}
          </div>
          <div style={{ display: 'flex', gap: 16, marginTop: 8, fontSize: 12, color: 'var(--text-dim)' }}>
            <span>
              <span className="trend-swatch input" /> 输入（含缓存写）
            </span>
            <span>
              <span className="trend-swatch output" /> 输出
            </span>
            <span style={{ marginLeft: 'auto', color: 'var(--text-faint)' }}>
              鼠标悬停查看每日明细；缓存读不计入柱高
            </span>
          </div>
        </>
      )}
    </Modal>
  )
}
