import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Star, Bell, BarChart2, Loader2 } from 'lucide-react';
import {
  AreaChart, Area, Bar, ComposedChart, Line, LineChart, XAxis, YAxis, Tooltip,
  ResponsiveContainer, CartesianGrid, ReferenceLine,
} from 'recharts';
import { useAppContext } from '../context/AppContext';
import {
  fetchChartBars, fetchResearchProfile, fetchResearchMetrics, fetchResearchEarnings,
  type OHLCVBar,
} from '../lib/marketApi';
import { SkeletonBlock, SkeletonText } from '../components/Skeleton';
import { Button } from '../components/ui/button';

// ─── Time period config ───────────────────────────────────────────────────────
const PERIODS = ['1D', '5D', '1M', '3M', '6M', 'YTD', '1Y', '5Y', 'MAX'] as const;
type Period = typeof PERIODS[number];
type IndicatorKey = 'rsi' | 'macd' | 'bollinger';

interface ChartPoint {
  ts: number;
  price: number;
  label: string;
  bollingerUpper?: number;
  bollingerMiddle?: number;
  bollingerLower?: number;
  rsi?: number;
  macd?: number;
  macdSignal?: number;
  macdHistogram?: number;
}

interface ResearchProfile {
  companyName?: string;
  sector?: string;
  industry?: string;
  description?: string;
  website?: string;
  mktCap?: number;
  revenue?: number;
  exchangeShortName?: string;
}

const EQUITY_EMPTY_STATE_SYMBOLS = ['AAPL','MSFT','GOOGL','AMZN','NVDA'];
const CRYPTO_EMPTY_STATE_SYMBOLS = ['BTC/USDT','ETH/USDT','SOL/USDT','ADA/USDT','DOGE/USDT'];
const CRYPTO_BASES = new Set(['BTC','ETH','SOL','ADA','DOGE','XRP','LTC','DOT','AVAX','MATIC','BNB']);

function uniqueSymbols(symbols: string[]) {
  return Array.from(new Set(symbols.map(s => s.trim().toUpperCase()).filter(Boolean)));
}

function splitSymbols(raw: unknown) {
  if (Array.isArray(raw)) return uniqueSymbols(raw.map(String));
  if (typeof raw === 'string') return uniqueSymbols(raw.split(','));
  return [];
}

function isCryptoLikeSymbol(symbol: string) {
  const normalized = symbol.trim().toUpperCase();
  const base = normalized.split(/[/-]/)[0];
  return normalized.includes('/') || normalized.endsWith('USDT') || CRYPTO_BASES.has(base);
}

function emptyStateSuggestions(profile: any, botSymbols: Record<string, unknown>) {
  const configuredSymbols = uniqueSymbols([
    ...splitSymbols(profile?.symbols),
    ...Object.keys(botSymbols ?? {}),
  ]);
  if (configuredSymbols.length > 0) return configuredSymbols.slice(0, 5);

  const marketHint = String(
    profile?.market_type ?? profile?.marketType ?? profile?.asset_class ?? profile?.assetClass ?? profile?.exchange ?? '',
  ).toLowerCase();
  if (marketHint.includes('crypto')) return CRYPTO_EMPTY_STATE_SYMBOLS;

  return EQUITY_EMPTY_STATE_SYMBOLS;
}

const INDICATORS: Array<{ key: IndicatorKey; label: string; hint: string }> = [
  { key: 'rsi', label: 'RSI', hint: '14-period momentum' },
  { key: 'macd', label: 'MACD', hint: '12/26 EMA trend' },
  { key: 'bollinger', label: 'Bollinger', hint: '20-period bands' },
];

// ─── Helpers ──────────────────────────────────────────────────────────────────
function formatPriceLabel(ts: number, period: Period) {
  const d = new Date(ts);
  if (period === '1D')    return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
  if (period === '5D')    return d.toLocaleDateString([], { weekday: 'short', hour: '2-digit', minute: '2-digit' });
  return d.toLocaleDateString([], { month: 'short', day: 'numeric' });
}

function formatAsOfTimestamp(ts: number | null) {
  if (ts == null) return 'Latest bar pending';

  return new Date(ts).toLocaleString('en-US', {
    timeZone: 'America/New_York',
    month: 'short',
    day: 'numeric',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function average(values: number[]) {
  return values.reduce((sum, value) => sum + value, 0) / values.length;
}

function calculateRsi(closes: number[], period = 14): Array<number | undefined> {
  const rsi: Array<number | undefined> = Array(closes.length).fill(undefined);
  if (closes.length <= period) return rsi;
  const fromAverages = (gain: number, loss: number) => {
    if (gain === 0 && loss === 0) return 50;
    if (loss === 0) return 100;
    return 100 - (100 / (1 + gain / loss));
  };

  let gainSum = 0;
  let lossSum = 0;
  for (let i = 1; i <= period; i += 1) {
    const change = closes[i] - closes[i - 1];
    gainSum += Math.max(change, 0);
    lossSum += Math.max(-change, 0);
  }

  let averageGain = gainSum / period;
  let averageLoss = lossSum / period;
  rsi[period] = fromAverages(averageGain, averageLoss);

  for (let i = period + 1; i < closes.length; i += 1) {
    const change = closes[i] - closes[i - 1];
    averageGain = ((averageGain * (period - 1)) + Math.max(change, 0)) / period;
    averageLoss = ((averageLoss * (period - 1)) + Math.max(-change, 0)) / period;
    rsi[i] = fromAverages(averageGain, averageLoss);
  }

  return rsi;
}

function calculateEma(values: number[], period: number): Array<number | undefined> {
  const ema: Array<number | undefined> = Array(values.length).fill(undefined);
  if (values.length < period) return ema;

  const multiplier = 2 / (period + 1);
  ema[period - 1] = average(values.slice(0, period));
  for (let i = period; i < values.length; i += 1) {
    ema[i] = (values[i] - ema[i - 1]!) * multiplier + ema[i - 1]!;
  }
  return ema;
}

function lastDefined(values: Array<number | undefined>) {
  for (let i = values.length - 1; i >= 0; i -= 1) {
    if (values[i] != null) return values[i];
  }
  return undefined;
}

function calculateMacd(closes: number[]) {
  const fast = calculateEma(closes, 12);
  const slow = calculateEma(closes, 26);
  const macd: Array<number | undefined> = closes.map((_, i) => (
    fast[i] != null && slow[i] != null ? fast[i]! - slow[i]! : undefined
  ));
  const signal: Array<number | undefined> = Array(closes.length).fill(undefined);
  const signalPeriod = 9;
  const signalMultiplier = 2 / (signalPeriod + 1);
  for (let i = 0; i < macd.length; i += 1) {
    if (macd[i] == null) continue;
    const recentMacd = macd.slice(0, i + 1).filter((value): value is number => value != null);
    if (recentMacd.length < signalPeriod) continue;
    const previousSignal = signal[i - 1];
    signal[i] = previousSignal == null
      ? average(recentMacd.slice(-signalPeriod))
      : (macd[i]! - previousSignal) * signalMultiplier + previousSignal;
  }
  const histogram = macd.map((value, i) => (
    value != null && signal[i] != null ? value - signal[i]! : undefined
  ));

  return { macd, signal, histogram };
}

function calculateBollingerBands(closes: number[], period = 20, deviations = 2) {
  const upper: Array<number | undefined> = Array(closes.length).fill(undefined);
  const middle: Array<number | undefined> = Array(closes.length).fill(undefined);
  const lower: Array<number | undefined> = Array(closes.length).fill(undefined);

  for (let i = period - 1; i < closes.length; i += 1) {
    const slice = closes.slice(i - period + 1, i + 1);
    const mean = average(slice);
    const variance = average(slice.map(value => (value - mean) ** 2));
    const standardDeviation = Math.sqrt(variance);
    middle[i] = mean;
    upper[i] = mean + standardDeviation * deviations;
    lower[i] = mean - standardDeviation * deviations;
  }

  return { upper, middle, lower };
}

function normalizeResearchProfile(profile: any): ResearchProfile | null {
  return Array.isArray(profile) ? profile[0] : profile;
}

// ─── Ticker header ────────────────────────────────────────────────────────────
export function TickerHeader({
  symbol,
  profile,
  latestBarTimestamp,
}: {
  symbol: string;
  profile?: ResearchProfile | null;
  latestBarTimestamp?: number | null;
}) {
  const navigate = useNavigate();
  const { botState } = useAppContext();
  const data = botState.symbols?.[symbol];
  const price = data?.price ?? 0;
  const change = data?.changeToday ?? 0;
  const changePct = price > 0 ? (change / (price - change)) * 100 : 0;
  const positive = change >= 0;
  const company = profile?.companyName;
  const companyName = typeof company === 'string' && company.trim() ? company.trim() : symbol;
  const exchange = typeof profile?.exchangeShortName === 'string' && profile.exchangeShortName.trim()
    ? profile.exchangeShortName.trim()
    : '—';

  return (
    <div style={{ marginBottom: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 4 }}>
        <h1 style={{ fontSize: 28, fontWeight: 800, color: 'var(--foreground)', margin: 0 }}>
          {symbol}
        </h1>
        <span style={{ fontSize: 13, color: 'var(--muted-foreground)', fontWeight: 500, marginTop: 4 }}>
          {companyName}
        </span>

        <div style={{ marginLeft: 'auto', display: 'flex', gap: 8 }}>
          <Button
            type="button"
            aria-label={`Open watchlist for ${symbol}`}
            onClick={() => navigate('/watchlist')}
            variant="outline"
            size="sm"
            style={{ borderRadius: 999 }}
          >
            <Star size={13} /> Watchlist
          </Button>
          <Button
            type="button"
            aria-label={`Open alerts for ${symbol}`}
            onClick={() => navigate('/alerts')}
            variant="outline"
            size="icon"
            style={{ borderRadius: '50%' }}
          >
            <Bell size={15} />
          </Button>
        </div>
      </div>

      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
        <span style={{ fontSize: 32, fontWeight: 800, color: 'var(--foreground)', letterSpacing: '-1px' }}>
          {price > 0 ? price.toFixed(2) : '—'}
        </span>
        {price > 0 && (
          <span style={{ fontSize: 15, fontWeight: 600, color: positive ? '#16A34A' : '#DC2626' }}>
            {positive ? '+' : ''}{change.toFixed(2)} ({positive ? '+' : ''}{changePct.toFixed(2)}%)
          </span>
        )}
      </div>

      <div style={{ fontSize: 11, color: 'var(--muted-foreground)', marginTop: 3 }}>
        {formatAsOfTimestamp(latestBarTimestamp ?? null)} ET · {exchange}
      </div>
    </div>
  );
}

// ─── Stock chart ──────────────────────────────────────────────────────────────
function StockChart({
  symbol,
  onLatestBarTimestamp,
  onBarsChange,
}: {
  symbol: string;
  onLatestBarTimestamp?: (timestamp: number | null) => void;
  onBarsChange?: (bars: OHLCVBar[]) => void;
}) {
  const [period, setPeriod] = useState<Period>('1Y');
  const [bars, setBars]     = useState<OHLCVBar[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError]   = useState<string | null>(null);
  const [enabledIndicators, setEnabledIndicators] = useState<Record<IndicatorKey, boolean>>({
    rsi: false,
    macd: false,
    bollinger: false,
  });

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setError(null);
    setBars([]);
    onLatestBarTimestamp?.(null);
    onBarsChange?.([]);
    fetchChartBars(symbol, period)
      .then(data => {
        if (!cancelled) {
          setBars(data);
          onLatestBarTimestamp?.(data.at(-1)?.ts ?? null);
          onBarsChange?.(data);
        }
      })
      .catch(err  => { if (!cancelled) setError(err?.message ?? 'Failed to load chart'); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [symbol, period, onLatestBarTimestamp, onBarsChange]);

  const closes = bars.map(b => b.close);
  const rsi = calculateRsi(closes);
  const macd = calculateMacd(closes);
  const bollinger = calculateBollingerBands(closes);

  const chartData: ChartPoint[] = bars.map((b, index) => ({
    ts:    b.ts,
    price: b.close,
    label: formatPriceLabel(b.ts, period),
    bollingerUpper: bollinger.upper[index],
    bollingerMiddle: bollinger.middle[index],
    bollingerLower: bollinger.lower[index],
    rsi: rsi[index],
    macd: macd.macd[index],
    macdSignal: macd.signal[index],
    macdHistogram: macd.histogram[index],
  }));

  const firstPrice = chartData[0]?.price ?? 0;
  const lastPrice  = chartData[chartData.length - 1]?.price ?? 0;
  const positive   = lastPrice >= firstPrice;
  const lineColor  = positive ? 'var(--primary)' : 'var(--destructive)';

  const priceYValues = chartData.flatMap(d => [
    d.price,
    ...(enabledIndicators.bollinger
      ? [d.bollingerUpper, d.bollingerMiddle, d.bollingerLower].filter((value): value is number => value != null)
      : []),
  ]);
  const macdValues = chartData.flatMap(d => (
    [d.macd, d.macdSignal, d.macdHistogram].filter((value): value is number => value != null)
  ));
  const minY = priceYValues.length ? Math.min(...priceYValues) : 0;
  const maxY = priceYValues.length ? Math.max(...priceYValues) : 100;
  const pad  = (maxY - minY) * 0.1 || 10;
  const macdMaxAbs = macdValues.length ? Math.max(...macdValues.map(value => Math.abs(value))) : 1;
  const enabledCount = Object.values(enabledIndicators).filter(Boolean).length;

  const toggleIndicator = (key: IndicatorKey) => {
    setEnabledIndicators(prev => ({ ...prev, [key]: !prev[key] }));
  };

  return (
    <div style={{
      background: 'var(--card)',
      borderRadius: 12,
      border: '1px solid var(--border)',
      padding: '16px 20px 12px',
      marginBottom: 20,
    }}>
      {/* Period selector + chart type */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12, gap: 12 }}>
        <div style={{ display: 'flex', gap: 2 }}>
          {PERIODS.map(p => (
            <button
              key={p}
              onClick={() => setPeriod(p)}
              style={{
                padding: '4px 9px',
                border: 'none',
                borderRadius: 6,
                fontSize: 12,
                fontWeight: period === p ? 700 : 500,
                background: period === p ? 'var(--accent-soft)' : 'transparent',
                color: period === p ? 'var(--primary)' : 'var(--muted-foreground)',
                cursor: 'pointer',
                transition: 'all 0.15s',
              }}
            >
              {p}
            </button>
          ))}
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, color: 'var(--muted-foreground)', fontSize: 12 }}>
          <div style={{ display: 'flex', gap: 6 }}>
            {INDICATORS.map(indicator => {
              const active = enabledIndicators[indicator.key];
              return (
                <button
                  key={indicator.key}
                  onClick={() => toggleIndicator(indicator.key)}
                  title={indicator.hint}
                  aria-pressed={active}
                  style={{
                    padding: '5px 9px',
                    borderRadius: 999,
                    border: active ? '1px solid var(--primary)' : '1px solid var(--border)',
                    background: active ? 'var(--accent-soft)' : 'var(--card)',
                    color: active ? 'var(--primary)' : 'var(--muted-foreground)',
                    fontSize: 11,
                    fontWeight: 700,
                    cursor: 'pointer',
                    boxShadow: active ? '0 2px 8px color-mix(in oklab, var(--primary) 18%, transparent 82%)' : 'none',
                  }}
                >
                  {indicator.label}
                </button>
              );
            })}
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
            <BarChart2 size={14} /> Line Chart
          </div>
        </div>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12 }}>
        <div style={{ fontSize: 11, color: 'var(--muted-foreground)' }}>
          Indicators: {enabledCount > 0 ? `${enabledCount} active` : 'none'}
        </div>
        <div style={{ fontSize: 11, color: 'var(--muted-foreground)' }}>
          RSI 14 · MACD 12/26/9 · Bollinger 20/2
        </div>
      </div>

      {/* Chart */}
      {loading ? (
        <div style={{
          height: 220, display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'center', gap: 10, color: 'var(--muted-foreground)',
        }}>
          <Loader2 size={28} color="var(--primary)" style={{ animation: 'spin 1s linear infinite' }} />
          <span style={{ fontSize: 13 }}>Loading chart…</span>
        </div>
      ) : error ? (
        <div style={{
          height: 220, display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'center', gap: 8, color: '#EF4444', fontSize: 13,
        }}>
          <BarChart2 size={32} color="#FCA5A5" />
          <span>{error}</span>
        </div>
      ) : chartData.length < 2 ? (
        <div style={{
          height: 220,
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center',
          justifyContent: 'center',
          color: 'var(--muted-foreground)',
          fontSize: 13,
          gap: 8,
        }}>
          <BarChart2 size={32} color="var(--muted-foreground)" />
          <span>No price data available for {symbol}</span>
        </div>
      ) : (
        <div>
            <ResponsiveContainer width="100%" height={220}>
              <AreaChart data={chartData} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
                <defs>
                  <linearGradient id="chartGrad" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="5%"  stopColor={lineColor} stopOpacity={0.15} />
                    <stop offset="95%" stopColor={lineColor} stopOpacity={0.01} />
                  </linearGradient>
                </defs>
                <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
                <XAxis
                  dataKey="label"
                  tick={{ fontSize: 10, fill: 'var(--muted-foreground)' }}
                  tickLine={false}
                  axisLine={false}
                  interval="preserveStartEnd"
                />
                <YAxis
                  domain={[minY - pad, maxY + pad]}
                  tick={{ fontSize: 10, fill: 'var(--muted-foreground)' }}
                  tickLine={false}
                  axisLine={false}
                  width={55}
                  tickFormatter={v => `$${v.toFixed(0)}`}
                />
                <Tooltip
                  contentStyle={{
                    background: 'var(--card-elevated)',
                    border: '1px solid var(--border)',
                    borderRadius: 8,
                    fontSize: 12,
                    boxShadow: 'var(--card-shadow)',
                  }}
                  formatter={(val: unknown, name: unknown) => {
                    const labels: Record<string, string> = {
                      price: 'Price',
                      bollingerUpper: 'BB Upper',
                      bollingerMiddle: 'BB Mid',
                      bollingerLower: 'BB Lower',
                    };
                    const key = String(name ?? '');
                    return [`$${Number(val).toFixed(2)}`, labels[key] ?? key];
                  }}
                  labelStyle={{ color: 'var(--muted-foreground)', fontSize: 11 }}
                />
                {enabledIndicators.bollinger && (
                  <>
                    <Line type="monotone" dataKey="bollingerUpper" stroke="#F59E0B" strokeWidth={1.4} dot={false} strokeDasharray="4 4" connectNulls />
                    <Line type="monotone" dataKey="bollingerMiddle" stroke="#FBBF24" strokeWidth={1.2} dot={false} strokeDasharray="2 4" connectNulls />
                    <Line type="monotone" dataKey="bollingerLower" stroke="#F59E0B" strokeWidth={1.4} dot={false} strokeDasharray="4 4" connectNulls />
                  </>
                )}
                <Area
                  type="monotone"
                  dataKey="price"
                  stroke={lineColor}
                  strokeWidth={2}
                  fill="url(#chartGrad)"
                  dot={false}
                  activeDot={{ r: 4, fill: lineColor, strokeWidth: 0 }}
                />
              </AreaChart>
            </ResponsiveContainer>

            {enabledIndicators.rsi && (
              <div style={{ marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--border)' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4, fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 700 }}>
                  <span>RSI (14)</span>
                  <span style={{ color: 'var(--muted-foreground)', fontWeight: 500 }}>70 overbought · 30 oversold</span>
                </div>
                <ResponsiveContainer width="100%" height={86}>
                  <LineChart data={chartData} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
                    <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
                    <XAxis dataKey="label" hide />
                    <YAxis domain={[0, 100]} tick={{ fontSize: 10, fill: 'var(--muted-foreground)' }} tickLine={false} axisLine={false} width={55} />
                    <Tooltip
                      contentStyle={{ background: 'var(--card-elevated)', border: '1px solid var(--border)', borderRadius: 8, fontSize: 12 }}
                      formatter={(val: unknown) => [Number(val).toFixed(1), 'RSI']}
                      labelStyle={{ color: 'var(--muted-foreground)', fontSize: 11 }}
                    />
                    <ReferenceLine y={70} stroke="#FCA5A5" strokeDasharray="3 3" />
                    <ReferenceLine y={30} stroke="#93C5FD" strokeDasharray="3 3" />
                    <Line type="monotone" dataKey="rsi" stroke="#7C3AED" strokeWidth={1.8} dot={false} connectNulls />
                  </LineChart>
                </ResponsiveContainer>
              </div>
            )}

            {enabledIndicators.macd && (
              <div style={{ marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--border)' }}>
                <div style={{ marginBottom: 4, fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 700 }}>
                  MACD (12, 26, 9)
                </div>
                <ResponsiveContainer width="100%" height={106}>
                  <ComposedChart data={chartData} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
                    <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
                    <XAxis dataKey="label" hide />
                    <YAxis
                      domain={[-macdMaxAbs * 1.2, macdMaxAbs * 1.2]}
                      tick={{ fontSize: 10, fill: 'var(--muted-foreground)' }}
                      tickLine={false}
                      axisLine={false}
                      width={55}
                    />
                    <Tooltip
                      contentStyle={{ background: 'var(--card-elevated)', border: '1px solid var(--border)', borderRadius: 8, fontSize: 12 }}
                      formatter={(val: unknown, name: unknown) => {
                        const labels: Record<string, string> = {
                          macdHistogram: 'Histogram',
                          macd: 'MACD',
                          macdSignal: 'Signal',
                        };
                        const key = String(name ?? '');
                        return [Number(val).toFixed(3), labels[key] ?? key];
                      }}
                      labelStyle={{ color: 'var(--muted-foreground)', fontSize: 11 }}
                    />
                    <ReferenceLine y={0} stroke="#CBD5E1" />
                    <Bar dataKey="macdHistogram" fill="#BFDBFE" radius={[2, 2, 0, 0]} />
                    <Line type="monotone" dataKey="macd" stroke="#2563EB" strokeWidth={1.7} dot={false} connectNulls />
                    <Line type="monotone" dataKey="macdSignal" stroke="#F97316" strokeWidth={1.5} dot={false} connectNulls />
                  </ComposedChart>
                </ResponsiveContainer>
              </div>
            )}
          </div>
      )}
    </div>
  );
}

// ─── Quick stats cards ────────────────────────────────────────────────────────
function QuickStats({ symbol, bars }: { symbol: string; bars: OHLCVBar[] }) {
  const { botState } = useAppContext();
  const d = botState.symbols?.[symbol];
  const closes = bars.map(bar => bar.close);
  const fallbackRsi = lastDefined(calculateRsi(closes));
  const fallbackEma50 = lastDefined(calculateEma(closes, 50));
  const fallbackEma200 = lastDefined(calculateEma(closes, 200));
  const rsi = d?.indicators?.rsi_1h ?? fallbackRsi;
  const ema50 = d?.indicators?.ema50_4h ?? fallbackEma50;
  const ema200 = d?.indicators?.ema200_4h ?? fallbackEma200;

  const stats = [
    { label: 'RSI (14)',   value: rsi != null ? rsi.toFixed(1) : '—' },
    { label: 'EMA 50',     value: ema50 != null ? ema50.toFixed(2) : '—' },
    { label: 'EMA 200',    value: ema200 != null ? ema200.toFixed(2) : '—' },
    { label: 'Signal',     value: d?.signal ?? '—' },
  ];

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))', gap: 12, marginBottom: 20 }}>
      {stats.map(s => (
        <div key={s.label} style={{
          background: 'var(--card)',
          borderRadius: 10,
          border: '1px solid var(--border)',
          padding: '12px 14px',
        }}>
          <div style={{ fontSize: 11, color: 'var(--muted-foreground)', fontWeight: 500, marginBottom: 4 }}>{s.label}</div>
          <div style={{ fontSize: 16, fontWeight: 700, color: 'var(--foreground)' }}>{s.value}</div>
        </div>
      ))}
    </div>
  );
}

// ─── Live research / financials cards (Phase 4) ───────────────────────────────
const fmtBig = (n: number | undefined) => {
  if (n == null || n === 0) return '—';
  if (Math.abs(n) >= 1e12) return `$${(n / 1e12).toFixed(2)}T`;
  if (Math.abs(n) >= 1e9)  return `$${(n / 1e9).toFixed(2)}B`;
  if (Math.abs(n) >= 1e6)  return `$${(n / 1e6).toFixed(2)}M`;
  return `$${n.toFixed(2)}`;
};

function ResearchCards({
  symbol,
  profile,
  profileLoading,
}: {
  symbol: string;
  profile: ResearchProfile | null;
  profileLoading: boolean;
}) {
  const [metrics,   setMetrics]   = useState<any>(null);
  const [earnings,  setEarnings]  = useState<any[]>([]);
  const [loading,   setLoading]   = useState(true);

  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    setMetrics(null); setEarnings([]);
    Promise.allSettled([
      fetchResearchMetrics(symbol),
      fetchResearchEarnings(symbol),
    ]).then(([m, e]) => {
      if (cancelled) return;
      if (m.status === 'fulfilled') setMetrics(Array.isArray(m.value) ? m.value[0] : m.value);
      if (e.status === 'fulfilled') setEarnings(e.value ?? []);
      setLoading(false);
    });
    return () => { cancelled = true; };
  }, [symbol]);

  const nextEarnings = earnings.find(e => e.date && new Date(e.date) >= new Date());
  const fmtDate = (d?: string) => d ? new Date(d).toLocaleDateString('en-US', { month:'short', day:'numeric', year:'numeric' }) : '—';
  const ValueSkeleton = ({ width = 58 }: { width?: number }) => <SkeletonBlock width={width} height={10} />;

  const financialRows: [string, string][] = [
    ['Market Cap',       fmtBig(profile?.mktCap)],
    ['Revenue (TTM)',    fmtBig(metrics?.revenuePerShareTTM != null && metrics?.sharesWSOQuarterly != null
      ? metrics.revenuePerShareTTM * metrics.sharesWSOQuarterly
      : profile?.revenue ?? undefined)],
    ['Net Income (TTM)', fmtBig(metrics?.netIncomePerShareTTM != null && metrics?.sharesWSOQuarterly != null
      ? metrics.netIncomePerShareTTM * metrics.sharesWSOQuarterly
      : undefined)],
    ['P/E Ratio (TTM)',  metrics?.peRatioTTM != null ? metrics.peRatioTTM.toFixed(1) : '—'],
    ['ROE (TTM)',        metrics?.roeTTM != null ? `${(metrics.roeTTM * 100).toFixed(1)}%` : '—'],
  ];

  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
      {/* Company Profile */}
      <div style={{ background: 'var(--card)', borderRadius: 12, border: '1px solid var(--border)', padding: 16 }}>
        <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foreground)', marginBottom: 10 }}>
          📋 Company
        </div>
        {profileLoading ? (
          <div role="status" aria-label="Loading company profile" style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <SkeletonText width="70%" />
            <SkeletonText width="96%" />
            <SkeletonText width="88%" />
            <SkeletonText width="55%" />
          </div>
        ) : profile ? (
          <>
            <div style={{ fontSize: 12, color: 'var(--foreground)', marginBottom: 6, lineHeight: 1.5 }}>
              <strong>{profile.companyName ?? symbol}</strong>
              {profile.sector && <> · {profile.sector}</>}
              {profile.industry && <> · {profile.industry}</>}
            </div>
            <div style={{ fontSize: 11, color: 'var(--muted-foreground)', lineHeight: 1.6, marginBottom: 8,
              display: '-webkit-box', WebkitLineClamp: 4, WebkitBoxOrient: 'vertical', overflow: 'hidden',
            }}>
              {profile.description ?? ''}
            </div>
            {profile.website && (
              <a href={profile.website} target="_blank" rel="noreferrer"
                style={{ fontSize: 11, color: 'var(--primary)', textDecoration: 'none' }}>
                {profile.website}
              </a>
            )}
          </>
        ) : (
          <div style={{ fontSize: 12, color: 'var(--muted-foreground)' }}>No profile data</div>
        )}
      </div>

      {/* Financials */}
      <div style={{ background: 'var(--card)', borderRadius: 12, border: '1px solid var(--border)', padding: 16 }}>
        <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foreground)', marginBottom: 10 }}>
          📊 Financials
        </div>
        {financialRows.map(([label, val]) => (
          <div key={label} style={{
            display: 'flex', justifyContent: 'space-between',
            padding: '5px 0', borderBottom: '1px solid var(--border)',
          }}>
            <span style={{ fontSize: 12, color: 'var(--muted-foreground)' }}>{label}</span>
            <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--foreground)' }}>
              {loading || profileLoading ? <ValueSkeleton width={label.length > 10 ? 64 : 46} /> : val}
            </span>
          </div>
        ))}
      </div>

      {/* Events / Earnings */}
      <div style={{ background: 'var(--card)', borderRadius: 12, border: '1px solid var(--border)', padding: 16 }}>
        <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--foreground)', marginBottom: 10 }}>
          📅 Events
        </div>
        {[
          ['Next Earnings',    loading ? '…' : fmtDate(nextEarnings?.date)],
          ['EPS Estimate',     loading ? '…' : nextEarnings?.epsEstimated != null ? `$${nextEarnings.epsEstimated.toFixed(2)}` : '—'],
          ['Revenue Est.',     loading ? '…' : nextEarnings?.revenueEstimated != null ? fmtBig(nextEarnings.revenueEstimated) : '—'],
          ['Exchange',         profileLoading ? '…' : profile?.exchangeShortName ?? '—'],
        ].map(([label, val]) => (
          <div key={label} style={{
            display: 'flex', justifyContent: 'space-between', alignItems: 'center',
            padding: '5px 0', borderBottom: '1px solid var(--border)',
          }}>
            <span style={{ fontSize: 12, color: 'var(--muted-foreground)' }}>{label}</span>
            <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--foreground)' }}>
              {val === '…' ? <ValueSkeleton width={label === 'Next Earnings' ? 82 : 52} /> : val}
            </span>
          </div>
        ))}
        {!loading && earnings.length > 0 && (
          <div style={{ marginTop: 10 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--foreground)', marginBottom: 4 }}>Past Earnings</div>
            {earnings.slice(0,3).map((e, i) => (
              <div key={i} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--muted-foreground)', padding: '2px 0' }}>
                <span>{fmtDate(e.date)}</span>
                <span style={{ color: e.eps >= (e.epsEstimated ?? e.eps) ? '#16A34A' : '#DC2626' }}>
                  EPS {e.eps != null ? `$${e.eps.toFixed(2)}` : '—'}
                </span>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Empty state ──────────────────────────────────────────────────────────────
function EmptyState({
  onSelect,
  suggestions,
}: {
  onSelect: (symbol: string) => void;
  suggestions: string[];
}) {
  const cryptoMode = suggestions.some(isCryptoLikeSymbol);

  return (
    <div style={{
      display: 'flex', flexDirection: 'column', alignItems: 'center',
      justifyContent: 'center', height: '60vh', gap: 16,
      color: 'var(--muted-foreground)',
    }}>
      <div style={{ fontSize: 56 }}>📈</div>
      <div style={{ fontSize: 20, fontWeight: 700, color: 'var(--foreground)' }}>
        Search an asset to get started
      </div>
      <div style={{ fontSize: 14, textAlign: 'center', maxWidth: 360 }}>
        Type a ticker symbol, crypto pair, or company name in the search bar above to view charts, financials, and news.
      </div>
      {cryptoMode && (
        <div style={{ fontSize: 12, color: 'var(--muted-foreground)', fontWeight: 600 }}>
          Suggested from your crypto bot configuration
        </div>
      )}
      <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
        {suggestions.map(t => (
          <button
            key={t}
            onClick={() => onSelect(t)}
            style={{
              padding: '4px 12px',
              background: 'var(--accent-soft)',
              color: 'var(--primary)',
              border: '1px solid var(--border)',
              borderRadius: 20,
              fontSize: 13,
              fontWeight: 600,
              cursor: 'pointer',
              fontFamily: 'inherit',
            }}
          >
            {t}
          </button>
        ))}
      </div>
    </div>
  );
}

// ─── HomeView ─────────────────────────────────────────────────────────────────
export function HomeView() {
  const { activeSymbol, setActiveSymbol, botState, profile: activeProfile } = useAppContext();
  const [profile, setProfile] = useState<ResearchProfile | null>(null);
  const [profileLoading, setProfileLoading] = useState(false);
  const [latestBarTimestamp, setLatestBarTimestamp] = useState<number | null>(null);
  const [chartBars, setChartBars] = useState<OHLCVBar[]>([]);

  useEffect(() => {
    if (!activeSymbol) {
      setProfile(null);
      setProfileLoading(false);
      return;
    }

    let cancelled = false;
    setProfile(null);
    setProfileLoading(true);
    fetchResearchProfile(activeSymbol)
      .then(data => {
        if (!cancelled) setProfile(normalizeResearchProfile(data));
      })
      .catch(() => {
        if (!cancelled) setProfile(null);
      })
      .finally(() => {
        if (!cancelled) setProfileLoading(false);
      });
    return () => { cancelled = true; };
  }, [activeSymbol]);

  if (!activeSymbol) {
    return (
      <EmptyState
        onSelect={setActiveSymbol}
        suggestions={emptyStateSuggestions(activeProfile, botState.symbols)}
      />
    );
  }

  return (
    <div>
      <TickerHeader symbol={activeSymbol} profile={profile} latestBarTimestamp={latestBarTimestamp} />
      <StockChart symbol={activeSymbol} onLatestBarTimestamp={setLatestBarTimestamp} onBarsChange={setChartBars} />
      <QuickStats symbol={activeSymbol} bars={chartBars} />
      <ResearchCards symbol={activeSymbol} profile={profile} profileLoading={profileLoading} />
    </div>
  );
}
