import { useEffect, useRef, useState } from "react";
import { useBackLayer } from "../../app/useBackLayer.js";
import { useI18n } from "../../shared/I18nProvider.jsx";
import { useOutsideDismiss } from "../../shared/hooks/useOutsideDismiss.js";
import { accountStatusLabel } from "../accounts/account-display.js";
import { AccountIdentity } from "../accounts/AccountIdentity.jsx";
import { formatRateWindowParts, formatUsageError, rateLimitTone } from "./status-state.js";
import { buildDailyTokenGrid, buildTokenMonthLabels, buildTokenPeriodGrid } from "./token-grid.js";
import { usageAccountLabel } from "./usage-account-label.js";
import { buildTrendAxisTicks, buildTrendPolylines, panTrendViewport, sortUsageAccounts, sortWeeklySummaryAccounts, trendHistoryStart } from "./usage-trend.js";
import { useUsageOverview } from "./useUsageOverview.js";
import { ResetCreditDialog } from "../../shared/ResetCreditDialog.jsx";
import { BackIcon, ClockIcon, SortDirectionIcon, SortIcon } from "../../shared/ActionIcons.jsx";

function UsageProgress({ value, label }) {
  const available = Number.isFinite(value);
  const percent = available ? Math.max(0, Math.min(100, value)) : 0;
  return <div className="usage-settings-progress" role="progressbar" aria-label={label} aria-valuemin="0" aria-valuemax="100" aria-valuenow={available ? percent : undefined}>
    <span style={{ width: `${percent}%` }} />
  </div>;
}

function LimitRow({ label, rateWindow, kind, loading, error, language, t }) {
  const parts = rateWindow ? formatRateWindowParts(rateWindow, kind, new Date(), language) : null;
  const unavailable = error ? formatUsageError(error, language) : t("usage.unavailable");
  const value = loading ? t("status.loading") : parts?.percent || unavailable;
  const detail = loading ? "" : parts?.detail || "";
  return <div className={`usage-settings-limit ${rateLimitTone(rateWindow)}`}>
    <div className="usage-settings-limit-heading"><strong>{label}</strong><span className="usage-settings-limit-meta"><span className="usage-settings-limit-value">{value}</span>{detail && <span className="usage-settings-detail">{detail}</span>}</span></div>
    <UsageProgress value={rateWindow?.remainingPercent} label={`${label} ${value}`} />
  </div>;
}

function UsageTrendChart({ points, days, until, historyError, language, onViewportChange, t }) {
  const width = 320;
  const height = 120;
  const inset = 10;
  const since = until - days * 24 * 60 * 60 * 1000;
  const gestureRef = useRef({ pointerId: null, start: null });
  const options = { since, until, width, height, inset };
  const primary = buildTrendPolylines(points, "primaryRemainingPercent", "primaryResetsAt", options);
  const secondary = buildTrendPolylines(points, "secondaryRemainingPercent", "secondaryResetsAt", options);
  const historyStart = trendHistoryStart(points);
  const hasHistory = historyStart !== null;
  const hasCurrentData = primary.length > 0 || secondary.length > 0;
  const axisTicks = buildTrendAxisTicks(since, until);
  function handlePointerDown(event) {
    if (gestureRef.current.pointerId !== null) return;
    event.currentTarget.setPointerCapture?.(event.pointerId);
    gestureRef.current = { pointerId: event.pointerId, start: { x: event.clientX, days, until } };
  }
  function handlePointerMove(event) {
    const gesture = gestureRef.current;
    if (gesture.pointerId !== event.pointerId || !gesture.start) return;
    const rect = event.currentTarget.getBoundingClientRect();
    onViewportChange({ days: gesture.start.days, until: panTrendViewport(gesture.start.until, gesture.start.days, event.clientX - gesture.start.x, rect.width, Date.now(), 30, historyStart) });
  }
  function handlePointerEnd(event) {
    if (gestureRef.current.pointerId !== event.pointerId) return;
    gestureRef.current = { pointerId: null, start: null };
    if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
  }
  return <div className="usage-trend">
    <div className="usage-trend-legend"><span className="primary">{t("usage.fiveHourRemaining")}</span><span className="secondary">{t("usage.weeklyRemaining")}</span></div>
    {hasHistory ? <>
      <div className="usage-trend-plot">
        <div className="usage-trend-scale" aria-hidden="true"><span>100%</span><span>50%</span><span>0%</span></div>
        <div className="usage-trend-canvas">
          <svg className="usage-trend-chart" viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" role="img" aria-label={t("usage.limitTrend")} onPointerDown={handlePointerDown} onPointerMove={handlePointerMove} onPointerUp={handlePointerEnd} onPointerCancel={handlePointerEnd}>
            {[100, 50, 0].map((value) => <line key={value} className="usage-trend-grid" x1={inset} x2={width - inset} y1={inset + (100 - value) / 100 * (height - inset * 2)} y2={inset + (100 - value) / 100 * (height - inset * 2)} />)}
            {axisTicks.map(({ at, position }) => <line key={at} className="usage-trend-grid vertical" x1={inset + position * (width - inset * 2)} x2={inset + position * (width - inset * 2)} y1={inset} y2={height - inset} />)}
            {primary.map((value, index) => <polyline key={`primary-${index}`} className="usage-trend-line primary" points={value} />)}
            {secondary.map((value, index) => <polyline key={`secondary-${index}`} className="usage-trend-line secondary" points={value} />)}
            <SingleTrendPoints values={primary} className="primary" />
            <SingleTrendPoints values={secondary} className="secondary" />
          </svg>
          {!hasCurrentData && <span className="usage-trend-no-data">{t("usage.noDataInRange")}</span>}
        </div>
      </div>
      <div className="usage-trend-axis">{axisTicks.map(({ at, position }) => <span key={at} style={{ left: `${position * 100}%` }}>{formatTrendAxis(at, days, language)}</span>)}</div>
    </> : <p className={`usage-trend-empty${historyError ? " error" : ""}`}>{historyError ? t("usage.historyUnavailable") : t("usage.collectingHistory")}</p>}
  </div>;
}

function WeeklySummary({ accounts, entries, accountMosaic, language, t }) {
  return <section className="settings-section usage-weekly-summary" aria-labelledby="usage-weekly-summary-title">
    <h2 id="usage-weekly-summary-title">{t("usage.weeklySummary")}</h2>
    <div className="usage-weekly-summary-list">
      {accounts.map((account) => {
        const window = entries[account.id]?.usage?.secondary;
        const parts = window ? formatRateWindowParts(window, "weekly", new Date(), language) : null;
        return <article key={account.id} className={`usage-weekly-summary-card ${rateLimitTone(window)}`}>
          <strong><AccountIdentity identity={usageAccountLabel(account, accounts)} mosaic={accountMosaic} /></strong>
          <span className="usage-weekly-summary-meta"><span className="usage-weekly-summary-value">{parts?.percent || t("usage.unavailable")}</span><span>{parts?.detail || t("usage.unavailable")}</span></span>
        </article>;
      })}
    </div>
  </section>;
}

function AccountDetailCard({ account, accounts, accountMosaic, entry = {}, language, onReset, t }) {
  const [resetOpen, setResetOpen] = useState(false);
  const usage = entry.usage;
  const accountName = usageAccountLabel(account, accounts);
  const credits = Number.isSafeInteger(usage?.resetCreditsAvailable) ? usage.resetCreditsAvailable : null;
  const expiry = earliestResetCreditExpiry(usage?.resetCredits);
  const expiryLabel = credits > 0
    ? expiry ? formatResetCreditExpiry(expiry, language, t) : t("usage.expiryUnavailable")
    : null;
  return <article className="usage-settings-card usage-account-detail">
    <div className="usage-settings-account"><strong><AccountIdentity identity={accountName} mosaic={accountMosaic} /></strong><span>{accountStatusLabel(account)}</span></div>
    <LimitRow label={t("usage.fiveHour")} rateWindow={usage?.primary} kind="primary" loading={entry.loading && !usage} error={entry.error} language={language} t={t} />
    <LimitRow label={t("status.weekly")} rateWindow={usage?.secondary} kind="weekly" loading={entry.loading && !usage} error={entry.error} language={language} t={t} />
    <div className="usage-credit-row"><strong>{t("usage.resetAvailableCount", { count: credits ?? t("usage.unavailable") })}</strong>{credits > 0 && <button className="usage-settings-action usage-credit-action" type="button" disabled={entry.resetPending} onClick={() => setResetOpen(true)}>{entry.resetPending ? t("context.using") : t("context.use")}</button>}</div>
    {expiryLabel && <span className={`usage-credit-expiry ${expiryTone(expiry)}`}>{expiry ? `${t("usage.earliestExpiry")} · ${expiryLabel}` : expiryLabel}</span>}
    <section className="usage-account-block"><AccountTokenGrid accountName={accountName} entry={entry} language={language} t={t} /></section>
    <AccountTrendBlock accountId={account.id} entry={entry} language={language} t={t} />
    <ResetCreditDialog open={resetOpen} accountName={accountName} onClose={() => setResetOpen(false)} onUse={() => onReset(account.id)} />
  </article>;
}

function AccountTrendBlock({ accountId, entry, language, t }) {
  const [days, setDays] = useState(0.25);
  const [until, setUntil] = useState(null);
  const [rangeMenuOpen, setRangeMenuOpen] = useState(false);
  const rangeMenuRef = useRef(null);
  const rangeButtonRef = useRef(null);
  const closeRangeMenu = useBackLayer(rangeMenuOpen, () => setRangeMenuOpen(false), `usage-range-menu-${accountId}`);
  useOutsideDismiss(rangeMenuRef, () => setRangeMenuOpen(false), rangeMenuOpen, { returnFocusRef: rangeButtonRef });
  const rangeOptions = [[0.125, t("usage.threeHours")], [0.25, t("usage.sixHours")], [0.5, t("usage.twelveHours")], [1, t("usage.oneDay")], [3, t("usage.threeDays")], [7, t("usage.sevenDays")], [30, t("usage.thirtyDays")]];
  const selectedRangeLabel = rangeOptions.find(([value]) => value === days)?.[1] ?? formatTrendDuration(days, language);
  function selectTrendDays(value) { setDays(value); setUntil(null); setRangeMenuOpen(false); }
  function updateTrendViewport(viewport) { setDays(viewport.days); setUntil(viewport.until); }
  return <section className="usage-account-block usage-account-trend-block">
    <div className="usage-account-block-heading"><h3>{t("usage.trendsTitle")}</h3><span className="usage-range-control" ref={rangeMenuRef}><button ref={rangeButtonRef} className="usage-range-trigger" type="button" aria-label={`${t("usage.trendRange")} · ${selectedRangeLabel}`} aria-haspopup="menu" aria-expanded={rangeMenuOpen} onClick={() => rangeMenuOpen ? closeRangeMenu() : setRangeMenuOpen(true)}><ClockIcon className="usage-range-icon" /></button>{rangeMenuOpen && <span className="usage-range-menu" role="menu">{rangeOptions.map(([value, label]) => <button key={value} type="button" role="menuitemradio" aria-checked={days === value} className={days === value ? "active" : ""} onClick={() => selectTrendDays(value)}>{label}</button>)}</span>}</span></div>
    <UsageTrendChart points={entry.points ?? []} days={days} until={until ?? Date.now()} historyError={entry.historyError} language={language} onViewportChange={updateTrendViewport} t={t} />
  </section>;
}

function AccountTokenGrid({ accountName, entry = {}, language, t }) {
  const [selected, setSelected] = useState(null);
  const [period, setPeriod] = useState("daily");
  const tokenScrollRef = useRef(null);
  const days = buildDailyTokenGrid(entry.tokenUsage?.dailyUsageBuckets, 182);
  const periodDays = buildTokenPeriodGrid(days, period);
  const monthLabels = buildTokenMonthLabels(days);
  const periodLabels = monthLabels;
  const periodColumnCount = Math.ceil(periodDays.length / 7);
  const selectedDay = selected ? periodDays.find((day) => tokenSelectionKey(day) === selected) : null;
  const periodOptions = [["daily", t("usage.daily")], ["weekly", t("usage.weekly")], ["cumulative", t("usage.cumulative")]];
  useEffect(() => {
    if (tokenScrollRef.current) tokenScrollRef.current.scrollLeft = tokenScrollRef.current.scrollWidth;
  }, [period]);
  return <div className="usage-token-card">
    <div className="usage-token-heading"><h3>{t("usage.dailyTokens")}</h3><div className="usage-token-period" role="group" aria-label={t("usage.tokenPeriod")}>{periodOptions.map(([value, label]) => <button key={value} type="button" className={period === value ? "active" : ""} aria-pressed={period === value} onClick={() => { setPeriod(value); setSelected(null); }}>{label}</button>)}</div></div>
    {entry.tokenError && !entry.tokenUsage ? <p className="usage-trend-empty error">{t("usage.unavailable")}</p> : <>
      <div className={`usage-token-chart${selectedDay ? " has-selection" : ""}`}>
        {selectedDay && <span className="usage-token-tooltip" role="status">{t("usage.tokenTooltip", { period: formatTokenTooltipPeriod(selectedDay, period, language, t), count: formatCompactTokenCount(selectedDay.tokens, language, t) })}</span>}
        <div className="usage-token-scroll" ref={tokenScrollRef}>
          <div className={`usage-token-grid ${period}`} style={{ gridTemplateColumns: `repeat(${periodColumnCount}, minmax(8px, 16px))` }} role="grid" aria-label={`${accountName} ${t("usage.dailyTokens")} ${periodOptions.find(([value]) => value === period)?.[1]}`}>
            {periodDays.map((day) => {
              const selectionKey = tokenSelectionKey(day);
              const selectable = period === "daily" || day.level > 0;
              return <button key={day.key ?? day.date} type="button" role="gridcell" className={`usage-token-cell usage-token-cell--level-${day.level}`} aria-label={`${formatTokenPeriod(day, language)} · ${formatTokens(day.tokens, language, t)}`} aria-pressed={selectable && selected === selectionKey} aria-disabled={!selectable} title={`${formatTokenPeriod(day, language)} · ${formatTokens(day.tokens, language, t)}`} onClick={() => { if (!selectable) return; setSelected(selected === selectionKey ? null : selectionKey); }} />;
            })}
          </div>
          <div className="usage-token-months" style={{ gridTemplateColumns: `repeat(${periodLabels.length}, minmax(0, 1fr))` }} aria-hidden="true">{periodLabels.map(({ date }) => <span key={date}>{formatTokenMonth(date, language)}</span>)}</div>
        </div>
      </div>
    </>}
  </div>;
}

export function UsageSettingsPage({ accounts = [], accountMosaic = false, onBack }) {
  const { language, t } = useI18n();
  const [sortMode, setSortMode] = useState("primary");
  const [sortDirection, setSortDirection] = useState("descending");
  const [sortMenuOpen, setSortMenuOpen] = useState(false);
  const sortMenuRef = useRef(null);
  const sortButtonRef = useRef(null);
  const closeSortMenu = useBackLayer(sortMenuOpen, () => setSortMenuOpen(false), "usage-sort-menu");
  useOutsideDismiss(sortMenuRef, () => setSortMenuOpen(false), sortMenuOpen, { returnFocusRef: sortButtonRef });
  const overview = useUsageOverview(accounts, 30);
  const sortedAccounts = sortUsageAccounts(accounts, overview.entries, sortMode, sortDirection);
  const weeklySummaryAccounts = sortWeeklySummaryAccounts(accounts, overview.entries);
  const sortOptions = [
    ["primary", t("usage.sortPrimary")],
    ["secondary", t("usage.sortSecondary")],
    ["configured", t("usage.sortConfigured")]
  ];
  const selectedSortLabel = sortOptions.find(([value]) => value === sortMode)?.[1];
  function selectSortMode(value) { setSortMode(value); setSortMenuOpen(false); }
  return <section className="settings-page usage-settings-page" aria-labelledby="usage-settings-title">
    <button type="button" className="screen-back conversation-back" aria-label={t("settings.back")} onClick={onBack}><BackIcon /></button>
    <div className="settings-content usage-settings-content">
      <h1 id="usage-settings-title" className="settings-prompt">{t("settings.usage")}</h1>
      {accounts.length > 0 && <WeeklySummary accounts={weeklySummaryAccounts} entries={overview.entries} accountMosaic={accountMosaic} language={language} t={t} />}
      <section className="settings-section" aria-labelledby="usage-account-title">
        <div className="usage-settings-heading"><h2 id="usage-account-title">{t("usage.accountDetails")}</h2><span className="usage-detail-actions"><span className="usage-sort-actions"><button className={`usage-sort-direction ${sortDirection}`} type="button" aria-label={t(sortDirection === "descending" ? "usage.sortDescending" : "usage.sortAscending")} onClick={() => setSortDirection(sortDirection === "descending" ? "ascending" : "descending")}><SortDirectionIcon /></button><span className="usage-sort-control" ref={sortMenuRef}><button ref={sortButtonRef} className="usage-sort-trigger" type="button" aria-label={`${t("usage.sort")} · ${selectedSortLabel}`} aria-haspopup="menu" aria-expanded={sortMenuOpen} onClick={() => sortMenuOpen ? closeSortMenu() : setSortMenuOpen(true)}><SortIcon /></button>{sortMenuOpen && <span className="usage-sort-menu" role="menu">{sortOptions.map(([value, label]) => <button key={value} type="button" role="menuitemradio" aria-checked={sortMode === value} className={sortMode === value ? "active" : ""} onClick={() => selectSortMode(value)}>{label}</button>)}</span>}</span></span></span></div>
        <div className="usage-account-list">
          {sortedAccounts.map((account) => <AccountDetailCard key={account.id} account={account} accounts={accounts} accountMosaic={accountMosaic} entry={overview.entries[account.id]} language={language} onReset={overview.reset} t={t} />)}
          {accounts.length === 0 && <p className="usage-trend-empty">{t("usage.noAccounts")}</p>}
        </div>
      </section>
      <button className="usage-settings-action usage-settings-refresh" type="button" disabled={overview.refreshing || accounts.length === 0} onClick={overview.reload}>{overview.refreshing ? t("status.loading") : t("usage.refresh")}</button>
    </div>
  </section>;
}

function earliestResetCreditExpiry(credits) {
  if (!Array.isArray(credits)) return null;
  return credits.reduce((earliest, credit) => {
    if (credit?.status && credit.status !== "available") return earliest;
    const expiresAt = Date.parse(credit?.expiresAt);
    if (!Number.isFinite(expiresAt)) return earliest;
    return earliest === null || expiresAt < earliest ? expiresAt : earliest;
  }, null);
}

function formatResetCreditExpiry(expiresAt, language, t) {
  const remaining = expiresAt - Date.now();
  const date = new Intl.DateTimeFormat(language, { month: "short", day: "numeric" }).format(expiresAt);
  if (remaining <= 0) return `${date} · ${t("usage.expired")}`;
  if (remaining <= 24 * 60 * 60 * 1000) return `${date} · ${t("usage.hoursLeft", { count: Math.ceil(remaining / (60 * 60 * 1000)) })}`;
  return `${date} · ${t("usage.daysLeft", { count: Math.ceil(remaining / (24 * 60 * 60 * 1000)) })}`;
}

function expiryTone(expiresAt) {
  if (!Number.isFinite(expiresAt)) return "";
  const remainingDays = (expiresAt - Date.now()) / (24 * 60 * 60 * 1000);
  if (remainingDays <= 3) return "urgent";
  if (remainingDays <= 7) return "warning";
  return "";
}

function SingleTrendPoints({ values, className }) {
  return values.flatMap((value, index) => {
    if (!value || value.includes(" ")) return [];
    const [cx, cy] = value.split(",").map(Number);
    return Number.isFinite(cx) && Number.isFinite(cy) ? [<circle key={index} className={`usage-trend-point ${className}`} cx={cx} cy={cy} r="3" />] : [];
  });
}

function formatTrendAxis(value, days, language) {
  return new Intl.DateTimeFormat(language, days <= 1 ? { hour: "2-digit", minute: "2-digit", hourCycle: "h23" } : { month: "numeric", day: "numeric" }).format(value);
}

function formatTrendDuration(days, language) {
  if (days >= 1) return `${Math.round(days * 10) / 10}${language === "ko" ? "일" : "d"}`;
  return `${Math.round(days * 24)}${language === "ko" ? "시간" : "h"}`;
}

function formatTokenDate(value, language) {
  const [year, month, day] = value.split("-").map(Number);
  return new Intl.DateTimeFormat(language, { month: "short", day: "numeric" }).format(new Date(year, month - 1, day));
}

function formatTokenMonth(value, language) {
  const [year, month] = value.split("-").map(Number);
  return new Intl.DateTimeFormat(language, { month: "short" }).format(new Date(year, month - 1, 1));
}

function formatTokenPeriod(period, language) {
  const startDate = period.periodStart ?? period.date;
  const endDate = period.periodEnd ?? period.date;
  const start = formatTokenDate(startDate, language);
  return endDate !== startDate ? `${start}–${formatTokenDate(endDate, language)}` : start;
}

function formatTokenTooltipPeriod(day, period, language, t) {
  const key = day.periodStart ?? day.date;
  const [year, month, date] = key.split("-").map(Number);
  const value = new Date(year, month - 1, date);
  const label = new Intl.DateTimeFormat(language, { year: "numeric", month: "long", day: "numeric" }).format(value);
  if (period === "cumulative") return t("usage.cumulativeThroughWeek", { date: label });
  return period === "weekly" ? t("usage.weekOf", { date: label }) : label;
}

function tokenSelectionKey(day) {
  return day.periodStart ?? day.date;
}

function formatCompactTokenCount(value, language, t) {
  if (!Number.isFinite(value)) return t("usage.unavailable");
  const formatted = new Intl.NumberFormat(language, { notation: "compact", maximumFractionDigits: 1 }).format(value);
  return language === "ko" ? `${formatted}개` : formatted;
}

function formatTokens(value, language, t) {
  return Number.isFinite(value) ? `${new Intl.NumberFormat(language).format(value)} ${t("usage.tokens")}` : t("usage.unavailable");
}
