/**
 * GoldenChart 암호화폐 추세검색 (Trend Search)
 */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import BuilderPageShell from './layout/BuilderPageShell';
import TrendSearchFilterPanel from './trendSearch/TrendSearchFilterPanel';
import TrendSearchResultsCardGrid from './trendSearch/TrendSearchResultsCardGrid';
import TrendSearchViewHeaderControls from './trendSearch/TrendSearchViewHeaderControls';
import type { TrendSearchDisplayMode } from './trendSearch/TrendSearchResultCard';
import type { Theme } from '../types';
import type { ChartRealtimeSource } from '../hooks/useChartRealtimeData';
import type { TickerData } from '../hooks/useMarketTicker';
import {
  DEFAULT_TREND_SEARCH_REQUEST,
  scanTrendSearch,
  loadTrendSearchResults,
  fetchTrendSearchDetail,
  type TrendSearchRequest,
  type TrendSearchResultDto,
} from '../utils/trendSearchApi';
import { sortTrendSearchByStrength } from '../utils/trendSearchMetrics';
import { resolveVirtualTargetNames } from '../utils/virtualTargetNames';
import { useVirtualTargetRegistry } from '../hooks/useVirtualTargetRegistry';
import { getAppSettingsCache, useAppSettings } from '../hooks/useAppSettings';
import {
  mergeFiltersFromTrendSearchSettings,
  mergeTrendSearchSettingsFromRequest,
  resolveTrendSearchAppSettings,
  trendSearchSettingsSignature,
  type TrendSearchAppSettings,
} from '../utils/trendSearchAppSettings';
import { autoAddTrendSearchTargets } from '../utils/trendSearchAutoAddTargets';
import '../styles/trendSearchDashboard.css';
import '../styles/virtualTradingDashboard.css';

const DISPLAY_MODE_KEY = 'tsd-display-mode';

function loadDisplayMode(): TrendSearchDisplayMode {
  try {
    const v = localStorage.getItem(DISPLAY_MODE_KEY);
    if (v === 'chart' || v === 'summary') return v;
  } catch { /* ignore */ }
  return 'summary';
}

interface Props {
  theme?: Theme;
  chartRealtimeSource?: ChartRealtimeSource;
  chartSeriesPriceLabels?: boolean;
  tickers?: Map<string, TickerData>;
}

const TrendSearchPage: React.FC<Props> = ({
  theme = 'dark',
  chartRealtimeSource = 'BACKEND_STOMP',
  chartSeriesPriceLabels = true,
  tickers,
}) => {
  const { defaults, isLoaded: appSettingsLoaded, save: saveAppSettings } = useAppSettings();
  const tsSettings = defaults.trendSearchSettings;
  const tsSettingsSig = trendSearchSettingsSignature(tsSettings);
  const [filters, setFilters] = useState<TrendSearchRequest>(() =>
    mergeFiltersFromTrendSearchSettings(
      { ...DEFAULT_TREND_SEARCH_REQUEST },
      resolveTrendSearchAppSettings(),
    ),
  );
  const [results, setResults] = useState<TrendSearchResultDto[]>([]);
  const [selectedMarket, setSelectedMarket] = useState<string | null>(null);
  const [searching, setSearching] = useState(false);
  const [displayMode, setDisplayMode] = useState<TrendSearchDisplayMode>(() => loadDisplayMode());
  const [flashMarkets, setFlashMarkets] = useState<Set<string>>(new Set());
  const [lastUpdatedAt, setLastUpdatedAt] = useState<number>(Date.now());
  const filtersRef = useRef(filters);
  filtersRef.current = filters;
  const tsSettingsRef = useRef(tsSettings);
  tsSettingsRef.current = tsSettings;
  const lastSyncedSettingsSigRef = useRef<string | null>(null);
  const schedulerSeededRef = useRef(false);
  const { isInTargets, isPinned, add, remove, busyMarket } = useVirtualTargetRegistry();

  useEffect(() => {
    if (!appSettingsLoaded) return;
    if (lastSyncedSettingsSigRef.current === tsSettingsSig) return;
    lastSyncedSettingsSigRef.current = tsSettingsSig;
    setFilters(prev => mergeFiltersFromTrendSearchSettings(prev, tsSettings));
  }, [appSettingsLoaded, tsSettingsSig, tsSettings]);

  useEffect(() => {
    if (!appSettingsLoaded || schedulerSeededRef.current) return;
    schedulerSeededRef.current = true;
    saveAppSettings({ trendSearchSettings: tsSettingsRef.current });
  }, [appSettingsLoaded, saveAppSettings]);

  const persistTrendSettings = useCallback((patch: Partial<TrendSearchAppSettings>) => {
    const base = resolveTrendSearchAppSettings(
      getAppSettingsCache().trendSearchSettings as Partial<TrendSearchAppSettings> | undefined,
    );
    const next = resolveTrendSearchAppSettings({ ...base, ...patch });
    lastSyncedSettingsSigRef.current = trendSearchSettingsSignature(next);
    saveAppSettings({ trendSearchSettings: next });
  }, [saveAppSettings]);

  const handleFiltersChange = useCallback((next: TrendSearchRequest) => {
    setFilters(next);
    const base = resolveTrendSearchAppSettings(
      getAppSettingsCache().trendSearchSettings as Partial<TrendSearchAppSettings> | undefined,
    );
    const merged = mergeTrendSearchSettingsFromRequest(base, next);
    lastSyncedSettingsSigRef.current = trendSearchSettingsSignature(merged);
    saveAppSettings({ trendSearchSettings: merged });
  }, [saveAppSettings]);

  const applyResults = useCallback(async (sorted: TrendSearchResultDto[], scannedAtMs?: number) => {
    setResults(sorted);
    setLastUpdatedAt(scannedAtMs ?? Date.now());
    setSelectedMarket(prev => {
      if (prev && sorted.some(r => r.market === prev)) return prev;
      return sorted[0]?.market ?? null;
    });
    if (sorted.length > 0) {
      setFlashMarkets(new Set(sorted.slice(0, 5).map(r => r.market)));
      setTimeout(() => setFlashMarkets(new Set()), 600);
    }
    await autoAddTrendSearchTargets(
      sorted,
      tsSettingsRef.current,
      filtersRef.current.timeframe,
    );
  }, []);

  const loadFromDb = useCallback(async (opts?: { silent?: boolean }) => {
    try {
      const payload = await loadTrendSearchResults();
      const sorted = sortTrendSearchByStrength(payload.results ?? []);
      const scannedAt = payload.scannedAt ? Date.parse(payload.scannedAt) : undefined;
      await applyResults(sorted, Number.isFinite(scannedAt) ? scannedAt : undefined);
    } catch (e) {
      console.warn('[TrendSearch] load results', e);
      if (!opts?.silent) window.alert('추세검색 결과를 불러오지 못했습니다. 백엔드 연결을 확인하세요.');
    }
  }, [applyResults]);

  const runScan = useCallback(async () => {
    setSearching(true);
    try {
      const list = await scanTrendSearch(filtersRef.current);
      const sorted = sortTrendSearchByStrength(list);
      await applyResults(sorted);
    } catch (e) {
      console.warn('[TrendSearch] scan', e);
      window.alert('추세검색 스캔에 실패했습니다. 백엔드 연결을 확인하세요.');
    } finally {
      setSearching(false);
    }
  }, [applyResults]);

  useEffect(() => {
    if (!appSettingsLoaded) return;
    void loadFromDb({ silent: true });
  }, [appSettingsLoaded, loadFromDb]);

  useEffect(() => {
    if (!tsSettings.autoRefreshEnabled) return;
    const ms = Math.max(1, tsSettings.autoRefreshSeconds) * 1000;
    const id = window.setInterval(() => void loadFromDb({ silent: true }), ms);
    return () => clearInterval(id);
  }, [tsSettings.autoRefreshEnabled, tsSettings.autoRefreshSeconds, loadFromDb]);

  useEffect(() => {
    try { localStorage.setItem(DISPLAY_MODE_KEY, displayMode); } catch { /* ignore */ }
  }, [displayMode]);

  const handleSelect = useCallback(async (row: TrendSearchResultDto) => {
    setSelectedMarket(row.market);
    try {
      const detail = await fetchTrendSearchDetail(row.market, filters.timeframe);
      if (detail) {
        setResults(prev => sortTrendSearchByStrength(
          prev.map(r => (r.market === detail.market ? detail : r)),
        ));
      }
    } catch { /* keep row */ }
  }, [filters.timeframe]);

  const handleAddTarget = useCallback((row: TrendSearchResultDto) => {
    const { koreanName, englishName } = resolveVirtualTargetNames(row.market, row.koreanName);
    void add(row.market, {
      koreanName,
      englishName,
      candleType: filtersRef.current.timeframe,
    });
  }, [add]);

  const handleRemoveTarget = useCallback((market: string) => {
    void remove(market);
  }, [remove]);

  const handleAutoAddToggle = useCallback((enabled: boolean) => {
    persistTrendSettings({ autoAddTargetsEnabled: enabled });
    if (enabled && results.length > 0) {
      void autoAddTrendSearchTargets(results, { ...tsSettingsRef.current, autoAddTargetsEnabled: true }, filtersRef.current.timeframe);
    }
  }, [persistTrendSettings, results]);

  const handleAutoRefreshToggle = useCallback((enabled: boolean) => {
    persistTrendSettings({ autoRefreshEnabled: enabled });
  }, [persistTrendSettings]);

  const handleRefreshSecondsChange = useCallback((sec: number) => {
    persistTrendSettings({ autoRefreshSeconds: sec });
  }, [persistTrendSettings]);

  return (
    <BuilderPageShell
      theme={theme}
      title="추세검색"
      subtitle="Golden Analysis · Trend Search"
      pageClassName="bps-page--tsd bps-page--vtd"
      banner={searching ? (
        <div className="tsd-search-loading" role="status" aria-live="polite" aria-busy="true">
          <div className="tsd-search-loading-track" role="progressbar" aria-label="추세검색 스캔 중">
            <div className="tsd-search-loading-fill" />
          </div>
          <span className="tsd-search-loading-label">추세검색 스캔 중…</span>
        </div>
      ) : undefined}
      headerActions={(
          <TrendSearchViewHeaderControls
            displayMode={displayMode}
            onDisplayModeChange={setDisplayMode}
            autoRefresh={tsSettings.autoRefreshEnabled}
            onAutoRefreshChange={handleAutoRefreshToggle}
            refreshSeconds={tsSettings.autoRefreshSeconds}
            onRefreshSecondsChange={handleRefreshSecondsChange}
            autoAddTargets={tsSettings.autoAddTargetsEnabled}
            onAutoAddTargetsChange={handleAutoAddToggle}
            searching={searching}
            onRefresh={() => void loadFromDb()}
            resultCount={results.length}
          />
        )}
        leftStorageKey="tsd-left-width"
        leftDefaultWidth={320}
        leftCollapsedStorageKey="tsd-left-open"
        collapsiblePanels
        left={(
          <TrendSearchFilterPanel
            filters={filters}
            onChange={handleFiltersChange}
            onSearch={() => void runScan()}
            searching={searching}
          />
        )}
        center={(
          <TrendSearchResultsCardGrid
            results={results}
            timeframe={filters.timeframe}
            displayMode={displayMode}
            selectedMarket={selectedMarket}
            onSelect={row => void handleSelect(row)}
            flashMarkets={flashMarkets}
            theme={theme}
            chartRealtimeSource={chartRealtimeSource}
            chartSeriesPriceLabels={chartSeriesPriceLabels}
            tickers={tickers}
            lastUpdatedAt={lastUpdatedAt}
            isInTargets={isInTargets}
            isPinned={isPinned}
            onAddTarget={handleAddTarget}
            onRemoveTarget={handleRemoveTarget}
            targetBusyMarket={busyMarket}
          />
        )}
      />
  );
};

export default TrendSearchPage;
