import { useMemo, useEffect, useState, lazy, Suspense } from 'react';
import { useParams } from 'react-router-dom';
import { useTickerDetail } from '../hooks/useTickerDetail';
import { useFetchSymbolData } from '../hooks/useFetchSymbolData';
import { useWatchlist, useAddToWatchlist, useRemoveFromWatchlist } from '../hooks/useWatchlist';
import { useTrades } from '../hooks/useTrades';
import { usePaperTrades } from '../hooks/usePaperTrades';
import { useActivation } from '../hooks/useActivation';
import { topPickSymbol, qualifiesSetup } from '../lib/qualification';
import type { FetchSelector } from '../api/ingestion';
import { CandlestickChart } from '../components/charts/CandlestickChart';
import { RadarChart, radarAxesFromDimensions } from '../components/charts/horizon';
import { ScoreCard } from '../components/ui/ScoreCard';
import { useTickerNames } from '../hooks/useTickers';
import { SkeletonCard } from '../components/ui/Skeleton';
import { SentimentPanel } from '../components/ticker/SentimentPanel';
import { FundamentalsPanel } from '../components/ticker/FundamentalsPanel';
import { IndicatorSelector } from '../components/ticker/IndicatorSelector';
import { RecommendationPanel } from '../components/ticker/RecommendationPanel';
import { ProductionRankStrip } from '../components/ticker/ProductionRankStrip';
import { Button } from '../components/ui/Button';
import { Callout } from '../components/ui/Callout';
import { formatPrice } from '../lib/format';
import type { TradeSetup } from '../lib/types';
import type { FieldPoint } from '../components/ticker/StandingMatrix';

// Lazy so recharts (heavy) ships in its own chunk, not the main ticker bundle.
const StandingMatrix = lazy(() => import('../components/ticker/StandingMatrix'));

const detailTabs = ['Analysis', 'Standing', 'Dimensions', 'Indicators', 'S/R Levels', 'Sentiment', 'Fundamentals'] as const;
type DetailTab = (typeof detailTabs)[number];

function SectionError({ message, onRetry }: { message: string; onRetry?: () => void }) {
  return (
    <Callout variant="error" onRetry={onRetry}>
      {message}
    </Callout>
  );
}

function StatusPill({ tone, label, title }: { tone: 'blue' | 'emerald'; label: string; title?: string }) {
  const tones = {
    blue: 'bg-blue-500/15 text-blue-300 border-blue-500/30',
    emerald: 'bg-emerald-500/15 text-emerald-300 border-emerald-500/30',
  } as const;
  return (
    <span
      title={title}
      className={`inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium ${tones[tone]}`}
    >
      {label}
    </span>
  );
}

function timeAgo(iso: string): string {
  const diff = Date.now() - new Date(iso).getTime();
  const mins = Math.floor(diff / 60_000);
  if (mins < 1) return 'just now';
  if (mins < 60) return `${mins}m ago`;
  const hrs = Math.floor(mins / 60);
  if (hrs < 24) return `${hrs}h ago`;
  const days = Math.floor(hrs / 24);
  return `${days}d ago`;
}

function marketDate(date = new Date()): string {
  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone: 'America/New_York',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).formatToParts(date);
  const value = (type: Intl.DateTimeFormatPartTypes) =>
    parts.find((part) => part.type === type)?.value ?? '';
  return value('year') + '-' + value('month') + '-' + value('day');
}

function formatSessionDate(isoDate: string): string {
  const currentMarketDate = marketDate();
  if (isoDate === currentMarketDate) return 'Today';

  // Parse date-only market sessions explicitly. Parsing YYYY-MM-DD directly as
  // a Date means midnight UTC and makes today's bar look many hours old.
  const [year, month, day] = isoDate.split('-').map(Number);
  if (!year || !month || !day) return isoDate;
  return new Intl.DateTimeFormat(undefined, {
    month: 'short',
    day: 'numeric',
    year: year === Number(currentMarketDate.slice(0, 4)) ? undefined : 'numeric',
    timeZone: 'UTC',
  }).format(new Date(Date.UTC(year, month - 1, day)));
}

function formatOHLCVFreshness(sessionDate: string, updatedAt?: string | null): string {
  const session = formatSessionDate(sessionDate);
  return updatedAt ? session + ' · updated ' + timeAgo(updatedAt) : session;
}

interface DataStatusItem {
  label: string;
  available: boolean;
  timestamp?: string | null;
  timestampLabel?: string | null;
  selector?: FetchSelector;  // what a refresh fetches; omit for rows with no manual refresh
  paid?: boolean;            // provider call that may cost money/quota
}

function RefreshIcon({ spinning }: { spinning: boolean }) {
  return (
    <svg className={`h-3.5 w-3.5 ${spinning ? 'animate-spin' : ''}`} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h5M20 20v-5h-5M4 9a8 8 0 0114-3M20 15a8 8 0 01-14 3" />
    </svg>
  );
}

function DataFreshnessBar({
  items,
  onRefresh,
  pendingLabel,
  busy,
}: {
  items: DataStatusItem[];
  onRefresh: (item: DataStatusItem) => void;
  pendingLabel: string | null;
  busy: boolean;
}) {
  return (
    <div className="flex flex-wrap gap-x-5 gap-y-2">
      {items.map((item) => (
        <div key={item.label} className="flex items-center gap-1.5">
          <span className={`inline-block h-2 w-2 rounded-full shrink-0 ${
            item.available ? 'bg-emerald-400 shadow-lg shadow-emerald-400/40' : 'bg-gray-600'
          }`} />
          <span className="text-xs text-gray-400">{item.label}</span>
          {item.available && item.timestamp ? (
            <span className="text-[10px] text-gray-500">{item.timestampLabel ?? timeAgo(item.timestamp)}</span>
          ) : !item.available ? (
            <span className="text-[10px] text-gray-600">no data</span>
          ) : null}
          {item.selector && (
            <button
              onClick={() => onRefresh(item)}
              disabled={busy}
              title={item.paid ? `Fetch ${item.label} (uses provider quota)` : `Recompute ${item.label}`}
              className="ml-0.5 text-gray-500 hover:text-blue-300 disabled:opacity-40 transition-colors"
            >
              <RefreshIcon spinning={pendingLabel === item.label} />
            </button>
          )}
          {item.paid && <span className="text-[9px] text-amber-500/70" title="Uses a paid/quota provider call">$</span>}
        </div>
      ))}
    </div>
  );
}

export default function TickerDetailPage() {
  const { symbol = '' } = useParams<{ symbol: string }>();
  const [showGateTraffic, setShowGateTraffic] = useState(false);
  const companyName = useTickerNames().get(symbol.toUpperCase());
  const {
    ohlcv,
    scores,
    srLevels,
    gateTargetLadder,
    sentiment,
    fundamentals,
    trades,
  } = useTickerDetail(symbol, showGateTraffic);
  const ingestion = useFetchSymbolData();
  const watchlist = useWatchlist();
  const addToWatchlist = useAddToWatchlist();
  const removeFromWatchlist = useRemoveFromWatchlist();
  const onWatchlist = useMemo(
    () => (watchlist.data ?? []).some((e) => e.symbol.toUpperCase() === symbol.toUpperCase()),
    [watchlist.data, symbol],
  );
  const watchlistBusy = addToWatchlist.isPending || removeFromWatchlist.isPending;

  // Status labels: is there an open paper trade on this ticker, and is it the
  // current top pick (same ranking the dashboard highlights)?
  const openTrades = usePaperTrades('open');
  // Full history for chart entry/exit arrows (open + closed on this symbol).
  const paperTradeHistory = usePaperTrades();
  const allTrades = useTrades();
  const activation = useActivation();
  const hasOpenTrade = useMemo(
    () => (openTrades.data ?? []).some((t) => t.symbol.toUpperCase() === symbol.toUpperCase()),
    [openTrades.data, symbol],
  );
  const symbolPaperTrades = useMemo(
    () =>
      (paperTradeHistory.data ?? []).filter(
        (t) => t.symbol.toUpperCase() === symbol.toUpperCase(),
      ),
    [paperTradeHistory.data, symbol],
  );
  const isTopPick = useMemo(
    () => topPickSymbol(allTrades.data, activation.data)?.toUpperCase() === symbol.toUpperCase(),
    [allTrades.data, activation.data, symbol],
  );

  const [activeTab, setActiveTab] = useState<DetailTab>('Analysis');
  const [refreshingLabel, setRefreshingLabel] = useState<string | null>(null);

  const dataStatus: DataStatusItem[] = useMemo(() => [
    {
      label: 'OHLCV',
      // Keep the market session date distinct from the last successful bar
      // write; treating YYYY-MM-DD as an instant makes today's session look old.
      available: !!ohlcv.data && ohlcv.data.length > 0,
      timestamp: ohlcv.data?.[ohlcv.data.length - 1]?.date,
      timestampLabel: ohlcv.data?.length
        ? formatOHLCVFreshness(
            ohlcv.data[ohlcv.data.length - 1].date,
            ohlcv.data[ohlcv.data.length - 1].created_at,
          )
        : null,
      selector: ['ohlcv'] as FetchSelector,
      paid: true,
    },
    {
      label: 'Sentiment',
      available: !!sentiment.data && sentiment.data.count > 0,
      timestamp: sentiment.data?.scores?.[0]?.timestamp,
      selector: ['sentiment'] as FetchSelector,
      paid: true,
    },
    {
      // Rebuilt for the whole universe by the nightly SEC + Dolt imports —
      // there is no per-ticker fetch to offer here.
      label: 'Fundamentals',
      available: !!fundamentals.data && fundamentals.data.fetched_at !== null,
      timestamp: fundamentals.data?.fetched_at,
    },
    {
      label: 'S/R Levels',
      available: !!srLevels.data && srLevels.data.count > 0,
      timestamp: srLevels.data?.levels?.[0]?.created_at,
      selector: 'recompute' as FetchSelector,
    },
    {
      label: 'Scores',
      available: !!scores.data && scores.data.composite_score !== null,
      timestamp: scores.data?.computed_at,
      selector: 'recompute' as FetchSelector,
    },
  ], [ohlcv.data, sentiment.data, fundamentals.data, srLevels.data, scores.data]);

  const handleRefresh = (item: DataStatusItem) => {
    if (!item.selector) return;
    setRefreshingLabel(item.label);
    ingestion.mutate(
      { symbol, sources: item.selector },
      { onSettled: () => setRefreshingLabel(null) },
    );
  };

  // Log trades API errors but don't disrupt the page
  useEffect(() => {
    if (trades.error) {
      console.error('Failed to fetch trade setups:', trades.error);
    }
  }, [trades.error]);

  const setupsForSymbol: TradeSetup[] = useMemo(() => {
    if (trades.error || !trades.data) return [];
    return trades.data.filter((t) => t.symbol.toUpperCase() === symbol.toUpperCase());
  }, [trades.data, trades.error, symbol]);

  const longSetup = useMemo(
    () => setupsForSymbol?.find((s) => s.direction === 'long'),
    [setupsForSymbol],
  );

  const shortSetup = useMemo(
    () => setupsForSymbol?.find((s) => s.direction === 'short'),
    [setupsForSymbol],
  );

  // Standing matrix: this ticker's residual momentum percentile + long confidence (from its
  // setup), the field (every ticker's composite × momentum) for the cloud, and
  // whether it qualifies / is the top pick.
  const myMomentum = longSetup?.momentum_percentile ?? shortSetup?.momentum_percentile ?? null;
  const myConfidence = longSetup?.confidence_score ?? null;
  const standingField = useMemo<FieldPoint[]>(() => {
    const seen = new Set<string>();
    const out: FieldPoint[] = [];
    for (const t of allTrades.data ?? []) {
      const s = t.symbol.toUpperCase();
      if (seen.has(s) || t.momentum_percentile == null) continue;
      seen.add(s);
      out.push({ symbol: s, composite: t.composite_score, momentum: t.momentum_percentile });
    }
    return out;
  }, [allTrades.data]);
  const standingStatus: 'top-pick' | 'qualified' | 'none' = useMemo(() => {
    if (isTopPick) return 'top-pick';
    if (longSetup && activation.data && qualifiesSetup(longSetup, activation.data)) return 'qualified';
    return 'none';
  }, [isTopPick, longSetup, activation.data]);
  const gateMomentum = activation.data?.min_momentum_percentile ?? 80;

  // Current price = latest close, with day-over-day change
  const priceInfo = useMemo(() => {
    const bars = ohlcv.data;
    if (!bars || bars.length === 0) return null;
    const last = bars[bars.length - 1];
    const prev = bars.length > 1 ? bars[bars.length - 2] : null;
    const change = prev && prev.close ? ((last.close - prev.close) / prev.close) * 100 : null;
    return { price: last.close, date: last.date, change };
  }, [ohlcv.data]);

  // Which setup the chart overlays. 'auto' = the ticker's preferred direction.
  const [overlayChoice, setOverlayChoice] = useState<'auto' | 'long' | 'short' | 'none'>('auto');

  // Target chosen in the recommendation ladder, per direction — the chart
  // overlay follows it.
  const [chosenTargets, setChosenTargets] = useState<{ long: number | null; short: number | null }>({
    long: null,
    short: null,
  });

  const action = (longSetup ?? shortSetup)?.recommended_action ?? null;
  const overlaySetup: TradeSetup | undefined = useMemo(() => {
    if (overlayChoice === 'none') return undefined;
    if (overlayChoice === 'long') return longSetup;
    if (overlayChoice === 'short') return shortSetup;
    // auto: preferred direction's setup, else the highest-confidence available
    if (action?.startsWith('LONG') && longSetup) return longSetup;
    if (action?.startsWith('SHORT') && shortSetup) return shortSetup;
    const candidates = [longSetup, shortSetup].filter(Boolean) as TradeSetup[];
    return candidates.sort((a, b) => (b.confidence_score ?? 0) - (a.confidence_score ?? 0))[0];
  }, [overlayChoice, longSetup, shortSetup, action]);

  // Chart overlay with the ladder-selected target applied (R:R from the ladder).
  const overlayWithTarget: TradeSetup | undefined = useMemo(() => {
    if (!overlaySetup) return undefined;
    const chosen = chosenTargets[overlaySetup.direction as 'long' | 'short'];
    if (chosen == null || chosen === overlaySetup.target) return overlaySetup;
    const ladder = overlaySetup.targets?.find((t) => t.price === chosen);
    return { ...overlaySetup, target: chosen, rr_ratio: ladder?.rr_ratio ?? overlaySetup.rr_ratio };
  }, [overlaySetup, chosenTargets]);

  // Sort visible S/R levels by strength for the table (only levels within chart zones)
  const sortedLevels = useMemo(() => {
    if (!srLevels.data?.visible_levels) return [];
    return [...srLevels.data.visible_levels].sort((a, b) => b.strength - a.strength);
  }, [srLevels.data]);

  return (
    <div className="space-y-6 animate-slide-up">
      {/* Drill-down header — identity + chips left, score fingerprint right */}
      <section className="glass overflow-hidden">
        {/* Data freshness — the very first row: how fresh is what I'm looking at */}
        <div className="border-b border-white/[0.06] px-6 py-2.5 sm:px-7">
          <DataFreshnessBar
            items={dataStatus}
            onRefresh={handleRefresh}
            pendingLabel={refreshingLabel}
            busy={ingestion.isPending}
          />
        </div>
        {fundamentals.data && !fundamentals.data.setup_eligible && (
          <div className="border-b border-white/[0.06] px-6 py-3 sm:px-7">
            <Callout variant="warning">
              <span className="font-medium">New setups paused.</span>{' '}
              {fundamentals.data.setup_block_reason ??
                'SEC fundamentals are incomplete for this ticker.'}
            </Callout>
          </div>
        )}
        <div className="p-6 pb-5 sm:p-7 sm:pb-5">
        <div className="flex flex-wrap items-start justify-between gap-x-8 gap-y-5">
          <div className="min-w-0">
            <p className="num text-[10.5px] uppercase tracking-[0.28em] text-gray-500">Ticker</p>
            <div className="mt-1.5 flex flex-wrap items-baseline gap-3">
              <h1 className="font-display text-4xl font-bold tracking-tight text-gray-100">
                {symbol.toUpperCase()}
              </h1>
              {companyName && (
                <span className="max-w-[260px] truncate text-sm text-gray-400">{companyName}</span>
              )}
            </div>
            {priceInfo && (
              <div className="mt-2 flex flex-wrap items-baseline gap-2.5">
                <span className="num text-2xl font-semibold text-gray-100">{formatPrice(priceInfo.price)}</span>
                {priceInfo.change !== null && (
                  <span className={`num text-sm font-medium ${priceInfo.change >= 0 ? 'text-emerald-300' : 'text-red-300'}`}>
                    {priceInfo.change >= 0 ? '+' : ''}{priceInfo.change.toFixed(2)}%
                  </span>
                )}
                <span className="text-xs text-gray-500">last close · {timeAgo(priceInfo.date)}</span>
              </div>
            )}
            <div className="mt-4 flex flex-wrap items-center gap-2">
              {scores.data?.composite_score != null && (
                <span className="rounded-full border border-white/[0.09] px-2.5 py-0.5 text-[11.5px] text-gray-400">
                  composite score {Math.round(scores.data.composite_score)}
                </span>
              )}
              {fundamentals.data?.next_earnings_date && (
                <span className="rounded-full border border-white/[0.09] px-2.5 py-0.5 text-[11.5px] text-gray-400">
                  earnings {new Date(fundamentals.data.next_earnings_date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
                </span>
              )}
              {isTopPick && (
                <StatusPill
                  tone="blue"
                  label="★ Top Pick"
                  title="Current top pick - highest production-ranked qualified setup right now"
                />
              )}
              {hasOpenTrade && (
                <StatusPill
                  tone="emerald"
                  label="● Open Trade"
                  title="You have an open paper trade on this ticker"
                />
              )}
            </div>
          </div>

          <div className="flex flex-col items-end gap-1">
            <div className="flex items-center gap-2">
              <Button
                variant="ghost"
                onClick={() =>
                  onWatchlist
                    ? removeFromWatchlist.mutate(symbol)
                    : addToWatchlist.mutate(symbol)
                }
                loading={watchlistBusy}
                disabled={watchlist.isLoading}
                title={onWatchlist ? 'Remove from watchlist' : 'Add to watchlist'}
                className={onWatchlist ? '!text-amber-300' : ''}
              >
                {onWatchlist ? '★ Watching' : '☆ Add to watchlist'}
              </Button>
              <Button
                onClick={() => { setRefreshingLabel(null); ingestion.mutate(symbol); }}
                loading={ingestion.isPending}
              >
                {ingestion.isPending ? 'Fetching…' : 'Fetch All'}
              </Button>
            </div>
            {scores.data && scores.data.dimensions.length >= 3 && (
              <RadarChart axes={radarAxesFromDimensions(scores.data.dimensions)} size={112} />
            )}
          </div>
        </div>
        </div>

        {/* Tab row — inline, hairline, overlay pills ride along on Analysis */}
        <div className="flex flex-wrap items-center gap-x-6 gap-y-1 border-b border-white/[0.06] px-6 sm:px-7" role="tablist" aria-label="Ticker sections">
          {detailTabs.map((t) => (
            <button
              key={t}
              role="tab"
              aria-selected={activeTab === t}
              onClick={() => setActiveTab(t)}
              className={`-mb-px border-b pb-2.5 text-[13px] font-medium transition-colors ${
                activeTab === t
                  ? 'border-blue-500 text-gray-100'
                  : 'border-transparent text-gray-400 hover:text-gray-200'
              }`}
            >
              {t}
            </button>
          ))}
          {activeTab === 'Analysis' && (longSetup || shortSetup) && (
            <span className="ml-auto flex items-center gap-1.5 pb-2 text-[11px]">
              <span className="text-gray-500">overlay</span>
              {([
                { key: 'auto', label: 'Auto', show: true },
                { key: 'long', label: 'Long', show: !!longSetup },
                { key: 'short', label: 'Short', show: !!shortSetup },
                { key: 'none', label: 'None', show: true },
              ] as const).filter((o) => o.show).map((o) => (
                <button
                  key={o.key}
                  onClick={() => setOverlayChoice(o.key)}
                  className={`rounded px-2 py-0.5 transition-colors ${
                    overlayChoice === o.key
                      ? 'bg-blue-400/15 text-blue-200'
                      : 'text-gray-500 hover:text-gray-300'
                  }`}
                >
                  {o.label}
                </button>
              ))}
            </span>
          )}
        </div>

        {/* Tab body */}
        <div className="p-6 pt-5 sm:p-7 sm:pt-5">
          {activeTab === 'Analysis' && (
            <div className="animate-fade-in">
        {ohlcv.isLoading && <SkeletonCard className="h-[440px]" />}
        {ohlcv.isError && (
          <SectionError
            message={ohlcv.error instanceof Error ? ohlcv.error.message : 'Failed to load OHLCV data'}
            onRetry={() => ohlcv.refetch()}
          />
        )}
        {ohlcv.data && (
          <>
            <CandlestickChart
              data={ohlcv.data}
              srLevels={srLevels.data?.levels}
              zones={srLevels.data?.zones}
              gateTargetLevels={gateTargetLadder.data?.levels}
              gateTargetLookbackBars={gateTargetLadder.data?.lookback_bars}
              gateTargetLoading={gateTargetLadder.isLoading && showGateTraffic}
              gateTargetError={gateTargetLadder.isError}
              showGateTraffic={showGateTraffic}
              onShowGateTrafficChange={setShowGateTraffic}
              tradeSetup={overlayWithTarget}
              currentPrice={priceInfo?.price}
              paperTrades={symbolPaperTrades}
            />
            <p className="mt-2 text-[11px] text-gray-500">
              Only the nearest support &amp; resistance are drawn. Full list in the S/R Levels tab.
              {srLevels.isError && ' S/R levels unavailable.'}
              {gateTargetLadder.isError && ' GTL diagnostic unavailable.'}
              {symbolPaperTrades.length > 0 && (
                <>
                  {' '}
                  <span className="text-emerald-400/90">▼</span> paper entry
                  {' · '}
                  <span className="text-red-400/90">▲</span> paper exit
                </>
              )}
            </p>
            <ProductionRankStrip
              setup={longSetup ?? shortSetup}
              momentumGate={gateMomentum}
            />
          </>
        )}
              {(longSetup || shortSetup) && (
                <div className="mt-8 border-t border-white/[0.06] pt-7">
                  <RecommendationPanel
                    frameless
                    symbol={symbol}
                    longSetup={longSetup}
                    shortSetup={shortSetup}
                    currentPrice={priceInfo?.price}
                    nextEarningsDate={fundamentals.data?.next_earnings_date}
                    selectedTargets={chosenTargets}
                    onSelectTarget={(direction, price) =>
                      setChosenTargets((s) => ({ ...s, [direction]: price }))
                    }
                  />
                </div>
              )}
            </div>
          )}

          {activeTab === 'Standing' && (
            <div className="hz-frameless animate-fade-in">
              {scores.isLoading && <SkeletonCard className="h-80" />}
              {scores.isError && (
                <SectionError message={scores.error instanceof Error ? scores.error.message : 'Failed to load scores'} onRetry={() => scores.refetch()} />
              )}
              {scores.data && (
                <>
                  <Suspense fallback={<SkeletonCard className="h-80" />}>
                    <StandingMatrix
                      symbol={symbol}
                      composite={scores.data.composite_score}
                      momentum={myMomentum}
                      field={standingField}
                      gateMomentum={gateMomentum}
                      status={standingStatus}
                      confidence={myConfidence}
                    />
                  </Suspense>
                  {(() => {
                    const cb = scores.data?.composite_breakdown;
                    const adj = cb?.sentiment_adjustment;
                    const base = cb?.base_score;
                    if (adj == null || base == null || Math.abs(adj) < 0.05) return null;
                    const composite = scores.data?.composite_score ?? base + adj;
                    return (
                      <p className="mt-3 text-center text-[11px] text-gray-500">
                        Composite{' '}
                        <span className="font-semibold text-gray-300">{Math.round(composite)}</span>
                        {' '}= Base {Math.round(base)}{' '}
                        {adj >= 0 ? '+' : '−'} Sentiment{' '}
                        <span className={adj >= 0 ? 'text-emerald-300/80' : 'text-red-300/80'}>
                          {Math.abs(adj).toFixed(1)}
                        </span>
                      </p>
                    );
                  })()}
                </>
              )}
            </div>
          )}

          {activeTab === 'Dimensions' && (
            <div className="hz-frameless animate-fade-in">
              {scores.isLoading && <SkeletonCard />}
              {scores.isError && (
                <SectionError message={scores.error instanceof Error ? scores.error.message : 'Failed to load scores'} onRetry={() => scores.refetch()} />
              )}
              {scores.data && (
                <ScoreCard showComposite={false} showRadar={false} compositeScore={scores.data.composite_score} dimensions={scores.data.dimensions} compositeBreakdown={scores.data.composite_breakdown} />
              )}
            </div>
          )}

          {activeTab === 'Indicators' && (
            <div className="hz-frameless animate-fade-in">
              <IndicatorSelector symbol={symbol} currentPrice={priceInfo?.price} />
            </div>
          )}

          {activeTab === 'S/R Levels' && (
            <div className="animate-fade-in">
              {sortedLevels.length === 0 ? (
                <Callout variant="empty">No S/R levels detected for this ticker yet.</Callout>
              ) : (
                <div className="overflow-x-auto">
                  <table className="w-full text-sm">
                    <thead>
                      <tr className="border-b border-white/[0.06] text-left text-xs uppercase tracking-wider text-gray-500">
                        <th className="px-4 py-3">Type</th>
                        <th className="px-4 py-3">Price Level</th>
                        <th className="px-4 py-3">Strength</th>
                        <th className="px-4 py-3">Method</th>
                      </tr>
                    </thead>
                    <tbody>
                      {sortedLevels.map((level) => (
                        <tr key={level.id} className="border-b border-white/[0.04] transition-colors duration-150 hover:bg-white/[0.03]">
                          <td className="px-4 py-3">
                            <span className={level.type === 'support' ? 'text-emerald-300' : 'text-gray-300'}>{level.type}</span>
                          </td>
                          <td className="px-4 py-3 text-gray-200 font-mono">{formatPrice(level.price_level)}</td>
                          <td className="px-4 py-3 text-gray-200">{level.strength}</td>
                          <td className="px-4 py-3 text-gray-400">{level.detection_method}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </div>
          )}

          {activeTab === 'Sentiment' && (
            <div className="hz-frameless animate-fade-in">
              {sentiment.isLoading && <SkeletonCard />}
              {sentiment.isError && (
                <SectionError message={sentiment.error instanceof Error ? sentiment.error.message : 'Failed to load sentiment'} onRetry={() => sentiment.refetch()} />
              )}
              {sentiment.data && <SentimentPanel data={sentiment.data} />}
            </div>
          )}

          {activeTab === 'Fundamentals' && (
            <div className="hz-frameless animate-fade-in">
              {fundamentals.isLoading && <SkeletonCard />}
              {fundamentals.isError && (
                <SectionError message={fundamentals.error instanceof Error ? fundamentals.error.message : 'Failed to load fundamentals'} onRetry={() => fundamentals.refetch()} />
              )}
              {fundamentals.data && <FundamentalsPanel data={fundamentals.data} />}
            </div>
          )}
        </div>

      </section>

    </div>
  );
}
