"use client";

import { useMemo } from "react";
import { useShallow } from "zustand/react/shallow";
import { LoadingSpinner } from "@/components/ui/loading-spinner";
import { ActivitySection } from "@/features/dashboard/components/ActivitySection";
import { DashboardAccessGate } from "@/features/dashboard/components/DashboardAccessGate";
import { DashboardSkeleton } from "@/features/dashboard/components/DashboardSkeleton";
import { HoldingsList } from "@/features/dashboard/components/HoldingsList";
import { MarketSummary } from "@/features/dashboard/components/MarketSummary";
import { StatusHeader } from "@/features/dashboard/components/StatusHeader";
import { StockDetailPreview } from "@/features/dashboard/components/StockDetailPreview";
import { useDashboardData } from "@/features/dashboard/hooks/use-dashboard-data";
import { useMarketRealtime } from "@/features/dashboard/hooks/use-market-realtime";
import { useKisWebSocketStore } from "@/features/kis-realtime/stores/kisWebSocketStore";
import { useKisRuntimeStore } from "@/features/settings/store/use-kis-runtime-store";
import { useHoldingsRealtime } from "@/features/dashboard/hooks/use-holdings-realtime";
import type {
  DashboardBalanceSummary,
  DashboardHoldingItem,
  DashboardMarketIndexItem,
} from "@/features/dashboard/types/dashboard.types";
import type { KisRealtimeStockTick } from "@/features/dashboard/utils/kis-stock-realtime.utils";

/**
 * @file DashboardContainer.tsx
 * @description 대시보드 메인 레이아웃 및 데이터 통합 관리 컴포넌트
 * @remarks
 * - [레이어] Components / Container
 * - [사용자 행동] 대시보드 진입 -> 전체 자산/시장 지수/보유 종목 확인 -> 특정 종목 선택 상세 확인
 * - [데이터 흐름] API(REST/WS) -> Hooks(useDashboardData, useMarketRealtime, useHoldingsRealtime) -> UI 병합 -> 하위 컴포넌트 전파
 * - [연관 파일] use-dashboard-data.ts, use-holdings-realtime.ts, StatusHeader.tsx, HoldingsList.tsx
 * @author jihoon87.lee
 */
export function DashboardContainer() {
  // [Store] KIS 런타임 설정 상태 (인증 여부, 접속 계좌, 웹소켓 정보 등)
  const {
    verifiedCredentials,
    isKisVerified,
    isKisProfileVerified,
    verifiedAccountNo,
    _hasHydrated,
    wsApprovalKey,
    wsUrl,
  } = useKisRuntimeStore(
    useShallow((state) => ({
      verifiedCredentials: state.verifiedCredentials,
      isKisVerified: state.isKisVerified,
      isKisProfileVerified: state.isKisProfileVerified,
      verifiedAccountNo: state.verifiedAccountNo,
      _hasHydrated: state._hasHydrated,
      wsApprovalKey: state.wsApprovalKey,
      wsUrl: state.wsUrl,
    })),
  );

  // KIS 접근 가능 여부 판단
  const canAccess = isKisVerified && Boolean(verifiedCredentials);

  // [Hooks] 기본적인 대시보드 데이터(잔고, 지수, 활동내역) 조회 및 선택 상태 관리
  // @see use-dashboard-data.ts - 초기 데이터 로딩 및 폴링 처리
  const {
    activity,
    balance,
    indices: initialIndices,
    selectedSymbol,
    setSelectedSymbol,
    isLoading,
    isRefreshing,
    activityError,
    balanceError,
    indicesError,
    lastUpdatedAt,
    refresh,
  } = useDashboardData(canAccess ? verifiedCredentials : null);

  // [Hooks] 시장 지수(코스피/코스닥) 실시간 웹소켓 데이터 구독
  // @see use-market-realtime.ts - 웹소켓 연결 및 지수 파싱
  const { realtimeIndices, isConnected: isWsConnected } = useMarketRealtime(
    verifiedCredentials,
    isKisVerified,
  );

  // [Hooks] 보유 종목 실시간 시세 웹소켓 데이터 구독
  // @see use-holdings-realtime.ts - 보유 종목 리스트 기반 시세 업데이트
  const { realtimeData: realtimeHoldings } = useHoldingsRealtime(
    balance?.holdings ?? [],
  );
  const reconnectWebSocket = useKisWebSocketStore((state) => state.reconnect);

  // [Step 1] REST API로 가져온 기본 지수 정보와 실시간 웹소켓 시세 병합
  const indices = useMemo(() => {
    if (initialIndices.length === 0) {
      return buildRealtimeOnlyIndices(realtimeIndices);
    }

    return initialIndices.map((item) => {
      const realtime = realtimeIndices[item.code];
      if (!realtime) return item;

      return {
        ...item,
        price: realtime.price,
        change: realtime.change,
        changeRate: realtime.changeRate,
      };
    });
  }, [initialIndices, realtimeIndices]);

  // [Step 2] 초기 잔고 데이터와 실시간 보유 종목 시세를 병합하여 손익 재계산
  const mergedHoldings = useMemo(
    () => mergeHoldingsWithRealtime(balance?.holdings ?? [], realtimeHoldings),
    [balance?.holdings, realtimeHoldings],
  );

  const isKisRestConnected = Boolean(
    (balance && !balanceError) ||
      (initialIndices.length > 0 && !indicesError) ||
      (activity && !activityError),
  );
  const hasRealtimeStreaming =
    Object.keys(realtimeIndices).length > 0 ||
    Object.keys(realtimeHoldings).length > 0;
  const isRealtimePending = Boolean(
    wsApprovalKey && wsUrl && isWsConnected && !hasRealtimeStreaming,
  );
  const effectiveIndicesError = indices.length === 0 ? indicesError : null;
  const indicesWarning =
    indices.length > 0 && indicesError
      ? "지수 API 재요청 중입니다. 화면 값은 실시간/최근 성공 데이터입니다."
      : null;

  /**
   * 대시보드 수동 새로고침 시 REST 조회 + 웹소켓 재연결을 함께 수행합니다.
   * @remarks UI 흐름: StatusHeader/각 카드 다시 불러오기 버튼 -> handleRefreshAll -> REST 재조회 + WS 완전 종료 후 재연결
   * @see features/dashboard/components/StatusHeader.tsx 상단 다시 불러오기 버튼
   * @see features/kis-realtime/stores/kisWebSocketStore.ts reconnect
   */
  const handleRefreshAll = async () => {
    await Promise.allSettled([
      refresh(),
      reconnectWebSocket({ refreshApproval: false }),
    ]);
  };

  /**
   * 실시간 보유종목 데이터를 기반으로 전체 자산 요약을 계산합니다.
   * @returns 실시간 요약 데이터 (총자산, 손익, 평가금액 등)
   */
  const mergedSummary = useMemo(
    () => buildRealtimeSummary(balance?.summary ?? null, mergedHoldings),
    [balance?.summary, mergedHoldings],
  );

  // [Step 3] 실시간 병합 데이터에서 현재 선택된 종목 정보를 추출
  // @see StockDetailPreview.tsx - 선택된 종목의 상세 정보 표시
  const realtimeSelectedHolding = useMemo(() => {
    if (!selectedSymbol || mergedHoldings.length === 0) return null;
    return (
      mergedHoldings.find((item) => item.symbol === selectedSymbol) ?? null
    );
  }, [mergedHoldings, selectedSymbol]);

  // 하이드레이션 이전에는 로딩 스피너 표시
  if (!_hasHydrated) {
    return (
      <div className="flex h-full items-center justify-center p-6">
        <LoadingSpinner />
      </div>
    );
  }

  // KIS 인증이 되지 않은 경우 접근 제한 게이트 표시
  if (!canAccess) {
    return <DashboardAccessGate canAccess={canAccess} />;
  }

  // 데이터 로딩 중이며 아직 데이터가 없는 경우 스켈레톤 표시
  if (isLoading && !balance && indices.length === 0) {
    return <DashboardSkeleton />;
  }

  return (
    <section className="mx-auto flex w-full max-w-7xl flex-col gap-4 p-4 md:p-6">
      {/* ========== 상단 상태 영역: 계좌 연결 정보 및 새로고침 ========== */}
      <StatusHeader
        summary={mergedSummary}
        isKisRestConnected={isKisRestConnected}
        isWebSocketReady={Boolean(wsApprovalKey && wsUrl && isWsConnected)}
        isRealtimePending={isRealtimePending}
        isProfileVerified={isKisProfileVerified}
        verifiedAccountNo={verifiedAccountNo}
        isRefreshing={isRefreshing}
        lastUpdatedAt={lastUpdatedAt}
        onRefresh={() => {
          void handleRefreshAll();
        }}
      />

      {/* ========== 메인 그리드 구성 ========== */}
      <div className="grid gap-4 lg:grid-cols-[1.15fr_1fr]">
        {/* 왼쪽 섹션: 보유 종목 목록 리스트 */}
        <HoldingsList
          holdings={mergedHoldings}
          selectedSymbol={selectedSymbol}
          isLoading={isLoading}
          error={balanceError}
          onRetry={() => {
            void handleRefreshAll();
          }}
          onSelect={setSelectedSymbol}
        />

        {/* 오른쪽 섹션: 시장 지수 요약 및 선택 종목 상세 정보 */}
        <div className="grid gap-4">
          {/* 시장 지수 현황 (코스피/코스닥) */}
          <MarketSummary
            items={indices}
            isLoading={isLoading}
            error={effectiveIndicesError}
            warning={indicesWarning}
            isRealtimePending={isRealtimePending}
            onRetry={() => {
              void handleRefreshAll();
            }}
          />

          {/* 선택된 종목의 실시간 상세 요약 정보 */}
          <StockDetailPreview
            holding={realtimeSelectedHolding}
            totalAmount={mergedSummary?.totalAmount ?? 0}
          />
        </div>
      </div>

      {/* ========== 하단 섹션: 최근 매매/충전 활동 내역 ========== */}
      <ActivitySection
        activity={activity}
        isLoading={isLoading}
        error={activityError}
        onRetry={() => {
          void handleRefreshAll();
        }}
      />
    </section>
  );
}

/**
 * @description REST 지수 데이터가 없을 때 실시간 수신값만으로 코스피/코스닥 표시 데이터를 구성합니다.
 * @param realtimeIndices 실시간 지수 맵
 * @returns 화면 렌더링용 지수 배열
 * @remarks UI 흐름: DashboardContainer -> buildRealtimeOnlyIndices -> MarketSummary 렌더링
 * @see features/dashboard/hooks/use-market-realtime.ts 실시간 지수 수신 훅
 */
function buildRealtimeOnlyIndices(
  realtimeIndices: Record<string, { price: number; change: number; changeRate: number }>,
) {
  const baseItems: DashboardMarketIndexItem[] = [
    { market: "KOSPI", code: "0001", name: "코스피", price: 0, change: 0, changeRate: 0 },
    { market: "KOSDAQ", code: "1001", name: "코스닥", price: 0, change: 0, changeRate: 0 },
  ];

  return baseItems
    .map((item) => {
      const realtime = realtimeIndices[item.code];
      if (!realtime) return null;
      return {
        ...item,
        price: realtime.price,
        change: realtime.change,
        changeRate: realtime.changeRate,
      } satisfies DashboardMarketIndexItem;
    })
    .filter((item): item is DashboardMarketIndexItem => Boolean(item));
}

/**
 * @description 보유종목 리스트에 실시간 체결가를 병합해 현재가/평가금액/손익을 재계산합니다.
 * @param holdings REST 기준 보유종목
 * @param realtimeHoldings 종목별 실시간 체결 데이터
 * @returns 병합된 보유종목 리스트
 * @remarks UI 흐름: DashboardContainer -> mergeHoldingsWithRealtime -> HoldingsList/StockDetailPreview 반영
 * @see features/dashboard/hooks/use-holdings-realtime.ts 보유종목 실시간 체결 구독
 */
function mergeHoldingsWithRealtime(
  holdings: DashboardHoldingItem[],
  realtimeHoldings: Record<string, KisRealtimeStockTick>,
) {
  if (holdings.length === 0 || Object.keys(realtimeHoldings).length === 0) {
    return holdings;
  }

  return holdings.map((item) => {
    const tick = realtimeHoldings[item.symbol];
    if (!tick) return item;

    const currentPrice = tick.currentPrice;
    const purchaseAmount = item.averagePrice * item.quantity;
    const evaluationAmount = currentPrice * item.quantity;
    const profitLoss = evaluationAmount - purchaseAmount;
    const profitRate = purchaseAmount > 0 ? (profitLoss / purchaseAmount) * 100 : 0;

    return {
      ...item,
      currentPrice,
      evaluationAmount,
      profitLoss,
      profitRate,
    };
  });
}

/**
 * @description 실시간 보유종목 기준으로 대시보드 요약(총자산/손익)을 일관되게 재계산합니다.
 * @param summary REST API 요약 값
 * @param holdings 실시간 병합된 보유종목
 * @returns 재계산된 요약 값
 * @remarks UI 흐름: DashboardContainer -> buildRealtimeSummary -> StatusHeader 카드 반영
 * @see features/dashboard/components/StatusHeader.tsx 상단 요약 렌더링
 */
function buildRealtimeSummary(
  summary: DashboardBalanceSummary | null,
  holdings: DashboardHoldingItem[],
) {
  if (!summary) return null;
  if (holdings.length === 0) return summary;

  const evaluationAmount = holdings.reduce(
    (total, item) => total + item.evaluationAmount,
    0,
  );
  const purchaseAmount = holdings.reduce(
    (total, item) => total + item.averagePrice * item.quantity,
    0,
  );
  const totalProfitLoss = evaluationAmount - purchaseAmount;
  const totalProfitRate =
    purchaseAmount > 0 ? (totalProfitLoss / purchaseAmount) * 100 : 0;

  const evaluationDelta = evaluationAmount - summary.evaluationAmount;
  const baseTotalAmount =
    summary.apiReportedNetAssetAmount > 0
      ? summary.apiReportedNetAssetAmount
      : summary.totalAmount;

  // 실시간은 "기준 순자산 + 평가금 증감분"으로만 반영합니다.
  const totalAmount = Math.max(baseTotalAmount + evaluationDelta, 0);
  const netAssetAmount = totalAmount;
  const cashBalance = Math.max(totalAmount - evaluationAmount, 0);

  return {
    ...summary,
    totalAmount,
    netAssetAmount,
    cashBalance,
    evaluationAmount,
    purchaseAmount,
    totalProfitLoss,
    totalProfitRate,
  } satisfies DashboardBalanceSummary;
}
