/**
 * useAppSettings
 *
 * 앱 전역 차트 기본 설정을 DB 와 동기화하는 훅.
 *
 * 관리 항목 (하드코딩 대체):
 *  - defaultSymbol    : 기본 종목 (DEFAULT_STATE.symbol)
 *  - defaultTimeframe : 기본 타임프레임 (DEFAULT_STATE.timeframe)
 *  - defaultChartType : 기본 차트 타입
 *  - defaultTheme     : 기본 테마
 *  - defaultLogScale  : 기본 로그 스케일
 *  - defaultLayoutId  : 기본 레이아웃 ID
 *  - mainChartStyle   : 캔들 색상 (DEFAULT_MAIN_CHART_STYLE)
 *  - syncOptions      : 멀티차트 동기화 옵션 (DEFAULT_SYNC)
 *
 * 사용 예:
 * ```tsx
 * const { settings, isLoaded, save } = useAppSettings();
 *
 * // 기본 심볼 사용
 * const symbol = settings.defaultSymbol ?? 'KRW-BTC';
 *
 * // 테마 변경 시 DB 에 저장
 * save({ defaultTheme: newTheme });
 * ```
 */

import { useCallback, useEffect, useRef, useState } from 'react';
import {
  loadAppSettings,
  saveAppSettings,
  type AppSettingsDto,
} from '../utils/backendApi';
import type { Theme, ChartType, Timeframe, MainChartStyle } from '../types';
import { resolveChartLegendOptions } from '../types/chartLegend';
import type { ChartLegendVisibility } from '../types/chartLegend';
import { DEFAULT_MAIN_CHART_STYLE } from '../utils/storage';
import { DEFAULT_SYNC, type SyncOptions } from '../utils/layoutTypes';
import { DEFAULT_DISPLAY_TIMEZONE, normalizeTimezone, setDisplayTimezone } from '../utils/timezone';

// 전역 캐시 — 여러 컴포넌트에서 공유하여 중복 요청 방지
let _cache: AppSettingsDto | null = null;
let _loadPromise: Promise<AppSettingsDto> | null = null;

function ensureLoaded(): Promise<AppSettingsDto> {
  if (_cache !== null) return Promise.resolve(_cache);
  if (_loadPromise) return _loadPromise;
  _loadPromise = loadAppSettings().then(data => {
    _cache = data ?? {};
    _loadPromise = null;
    return _cache;
  });
  return _loadPromise;
}

export function invalidateAppSettingsCache() {
  _cache = null;
  _loadPromise = null;
}

// ─────────────────────────────────────────────────────────────────────────────

/** DB 또는 fallback 기본값 접근 헬퍼 */
export function resolveAppDefaults(s: AppSettingsDto) {
  return {
    symbol:        (s.defaultSymbol    ?? 'KRW-BTC')    as string,
    timeframe:     (s.defaultTimeframe ?? '1D')          as Timeframe,
    chartType:     (s.defaultChartType ?? 'candlestick') as ChartType,
    theme:         (s.defaultTheme     ?? 'dark')        as Theme,
    logScale:      s.defaultLogScale   ?? false,
    layoutId:      s.defaultLayoutId   ?? '1',
    mainChartStyle:(s.mainChartStyle as unknown as MainChartStyle | null) ?? DEFAULT_MAIN_CHART_STYLE,
    syncOptions:   (s.syncOptions as unknown as SyncOptions | null) ?? DEFAULT_SYNC,
    btAutoPopup:      s.btAutoPopup      ?? true,
    btShowPrice:      s.btShowPrice      ?? true,
    chartSeriesPriceLabels: s.chartSeriesPriceLabels ?? true,
    chartVolumeVisible:     s.chartVolumeVisible ?? true,
    chartLegendOptions:     resolveChartLegendOptions(
      s.chartLegendOptions as Partial<ChartLegendVisibility> | null | undefined,
    ),
    tradeAlertPopup:  s.tradeAlertPopup  ?? true,
    tradeAlertSoundEnabled: s.tradeAlertSoundEnabled ?? true,
    tradeAlertSound:  s.tradeAlertSound  ?? 'bell',
    tradeAlertPopupPosition: s.tradeAlertPopupPosition ?? 'right',
    tradeAlertPopupLayout:   s.tradeAlertPopupLayout   ?? 'stack',
    tradeAlertPopupGridCols: s.tradeAlertPopupGridCols ?? 2,
    liveStrategyCheck:  s.liveStrategyCheck  ?? false,
    liveStrategyId:     s.liveStrategyId     ?? null,
    liveExecutionType:  s.liveExecutionType  ?? 'CANDLE_CLOSE',
    livePositionMode:   s.livePositionMode   ?? 'LONG_ONLY',
    paperTradingEnabled:     s.paperTradingEnabled     ?? true,
    paperInitialCapital:     s.paperInitialCapital     ?? 10_000_000,
    paperFeeRatePct:         s.paperFeeRatePct         ?? 0.05,
    paperSlippagePct:        s.paperSlippagePct        ?? 0,
    paperMinOrderKrw:        s.paperMinOrderKrw        ?? 5000,
    paperAutoTradeEnabled:   s.paperAutoTradeEnabled   ?? false,
    paperAutoTradeBudgetPct: s.paperAutoTradeBudgetPct ?? 95,
    tradingMode:            s.tradingMode            ?? 'PAPER',
    liveAutoTradeEnabled:   s.liveAutoTradeEnabled   ?? false,
    hasUpbitKeys:           s.hasUpbitKeys           ?? false,
    upbitAccessKeyMasked:   s.upbitAccessKeyMasked   ?? null,
    chartRealtimeSource:    s.chartRealtimeSource    ?? 'BACKEND_STOMP',
    liveAutoTradeBudgetPct: s.liveAutoTradeBudgetPct ?? 95,
    fcmPushEnabled:         s.fcmPushEnabled         ?? false,
    displayTimezone:        normalizeTimezone(s.displayTimezone ?? DEFAULT_DISPLAY_TIMEZONE),
  };
}

// ─────────────────────────────────────────────────────────────────────────────

/** sessionKey 변경 시(로그인/로그아웃) 설정을 DB에서 다시 로드 */
export function useAppSettings(sessionKey = 0) {
  const [settings, setSettings] = useState<AppSettingsDto>(_cache ?? {});
  const [isLoaded, setIsLoaded] = useState(false);
  const mountedRef = useRef(true);

  useEffect(() => {
    mountedRef.current = true;
    setIsLoaded(false);
    invalidateAppSettingsCache();
    ensureLoaded().then(data => {
      if (mountedRef.current) {
        setSettings(data);
        setDisplayTimezone(normalizeTimezone(data.displayTimezone ?? DEFAULT_DISPLAY_TIMEZONE));
        setIsLoaded(true);
      }
    }).catch(err => {
      console.error('[useAppSettings] load failed', err);
      if (mountedRef.current) setIsLoaded(true);
    });
    return () => { mountedRef.current = false; };
  }, [sessionKey]);

  /**
   * 특정 필드를 DB 에 저장하고 로컬 캐시를 업데이트.
   * 낙관적 업데이트 — DB 저장 실패해도 UI 는 즉시 반영.
   */
  const save = useCallback((patch: AppSettingsDto) => {
    const merged = { ...(_cache ?? {}), ...patch };
    _cache = merged;
    setSettings(merged);
    if (patch.displayTimezone != null) {
      setDisplayTimezone(normalizeTimezone(patch.displayTimezone));
    }
    saveAppSettings(patch).then(updated => {
      if (updated && mountedRef.current) {
        _cache = { ...(_cache ?? {}), ...updated };
        setSettings(prev => ({ ...prev, ...updated }));
      }
    }).catch(err =>
      console.error('[useAppSettings] save failed', err)
    );
  }, []);

  /** 로드된 설정의 해석된 기본값 */
  const defaults = resolveAppDefaults(settings);

  return { settings, defaults, isLoaded, save };
}
