import { css, keyframes } from '@emotion/react';
import { memo, useEffect, useRef, useState } from 'react';
import { adaptive } from '../../styles/adaptive';
import { FloatingOverlay } from '../FloatingOverlay';
import { useFloatingItems } from '../../hooks/useFloatingItems';
import elementsData from '../../data/elements.json';
import recipesData from '../../data/recipes.json';
import { CharacterSprite } from '../CharacterSprite';
import { useIdleMood, type Mood } from '../../lib/useIdleMood';
import {
  calcResonanceBonuses,
  calcTierAutomationStatus,
  countDiscoveredByTier,
  calcEffectiveIdleRate,
  calcEnhanceCost,
  calcSpawnRate,
  DAILY_MISSIONS,
  ENHANCE_MAX_LEVEL,
  getDailyMissionProgress,
  getDiscoveredElementIds,
  isElementUnlocked,
  TIER_AUTOMATION_GOALS,
  useGameStore,
} from '../../store/useGameStore';

// 원소 상태 분류
type ElementState = 'obtained' | 'locked' | 'undiscovered';

// 골드 금액 표시 포맷
function formatGold(amount: number): string {
  if (amount >= 1_000_000) return `${(amount / 1_000_000).toFixed(1)}M`;
  if (amount >= 1_000) return `${(amount / 1_000).toFixed(1)}K`;
  return String(amount);
}

function formatSeconds(seconds: number): string {
  if (!Number.isFinite(seconds)) return '-';
  if (seconds < 1) return '<1초';
  if (seconds < 60) return `${Math.ceil(seconds)}초`;
  return `${Math.ceil(seconds / 60)}분`;
}

function formatBoostTime(ms: number): string {
  return formatSeconds(Math.max(0, Math.ceil(ms / 1000)));
}

function formatRemaining(ms: number): string {
  const seconds = Math.max(0, Math.ceil(ms / 1000));
  if (seconds >= 3600) {
    const h = Math.floor(seconds / 3600);
    const m = Math.floor((seconds % 3600) / 60);
    return `${h}시간 ${m}분`;
  }
  return formatSeconds(seconds);
}

// ────────────────────────────────────────────────────────────
// Styles
// ────────────────────────────────────────────────────────────

const containerStyle = css`
  padding: 20px;
  background: ${adaptive.background};
  min-height: 100%;
`;

const headerStyle = css`
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
`;

const titleStyle = css`
  font-size: 20px;
  font-weight: 700;
  color: ${adaptive.grey900};
  margin: 0;
`;

const goldBadgeStyle = css`
  display: flex;
  align-items: center;
  gap: 4px;
  background: linear-gradient(135deg, #ffd700, #ffaa00);
  padding: 6px 12px;
  border-radius: 16px;
  font-size: 14px;
  font-weight: 700;
  color: #5a3200;
`;

const progressBarWrapStyle = css`
  background: ${adaptive.greyBackground};
  border-radius: 10px;
  padding: 10px 14px;
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
`;

const progressHeaderStyle = css`
  display: flex;
  justify-content: space-between;
  align-items: center;
`;

const progressLabelStyle = css`
  font-size: 12px;
  color: ${adaptive.grey500};
  font-weight: 500;
`;

const progressCountStyle = css`
  font-size: 13px;
  font-weight: 700;
  color: ${adaptive.blue500};
`;

const progressTrackStyle = css`
  height: 6px;
  background: ${adaptive.grey200};
  border-radius: 3px;
  overflow: hidden;
`;

const progressFillStyle = (ratio: number) => css`
  height: 100%;
  width: ${(ratio * 100).toFixed(1)}%;
  background: linear-gradient(90deg, #3182f6, #7c4dff);
  border-radius: 3px;
  transition: width 0.3s ease;
`;

const dailyPanelStyle = css`
  background: #ffffff;
  border: 1px solid ${adaptive.grey200};
  border-radius: 16px;
  padding: 14px;
  margin-bottom: 16px;
  box-shadow: 0 8px 20px rgba(49, 64, 84, 0.06);
`;

const dailyHeaderStyle = css`
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
`;

const dailyTitleStyle = css`
  font-size: 14px;
  font-weight: 900;
  color: ${adaptive.grey900};
`;

const dailyStreakStyle = css`
  border-radius: 999px;
  background: #fff3cd;
  color: #8a5a00;
  padding: 5px 9px;
  font-size: 11px;
  font-weight: 900;
  white-space: nowrap;
`;

const dailyBonusRowStyle = css`
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: center;
  background: linear-gradient(135deg, #f0f7ff, #f8fbff);
  border-radius: 12px;
  padding: 10px 12px;
  margin-bottom: 10px;
`;

const dailyBonusTextStyle = css`
  min-width: 0;
`;

const dailyBonusNameStyle = css`
  font-size: 13px;
  font-weight: 900;
  color: ${adaptive.grey900};
`;

const dailyBonusDescStyle = css`
  margin-top: 2px;
  font-size: 11px;
  font-weight: 700;
  color: ${adaptive.grey500};
`;

const compactButtonStyle = (active: boolean) => css`
  border: none;
  border-radius: 10px;
  background: ${active ? adaptive.blue500 : adaptive.grey200};
  color: ${active ? '#ffffff' : adaptive.grey500};
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 900;
  cursor: ${active ? 'pointer' : 'default'};
  white-space: nowrap;
`;

const missionListStyle = css`
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;

  @media (max-width: 520px) {
    grid-template-columns: 1fr;
  }
`;

const missionCardStyle = (done: boolean, claimed: boolean) => css`
  border-radius: 12px;
  border: 1px solid ${claimed ? '#8bd5a2' : done ? adaptive.blue500 : adaptive.grey200};
  background: ${claimed ? '#f0fff4' : done ? '#f0f7ff' : adaptive.greyBackground};
  padding: 10px;
`;

const missionNameStyle = css`
  font-size: 12px;
  font-weight: 900;
  color: ${adaptive.grey900};
  margin-bottom: 3px;
`;

const missionDescStyle = css`
  font-size: 10px;
  line-height: 1.35;
  font-weight: 700;
  color: ${adaptive.grey500};
`;

const missionProgressStyle = css`
  height: 5px;
  border-radius: 999px;
  background: ${adaptive.grey200};
  overflow: hidden;
  margin: 8px 0 7px;
`;

const missionProgressFillStyle = (ratio: number) => css`
  height: 100%;
  width: ${(Math.min(1, Math.max(0, ratio)) * 100).toFixed(1)}%;
  border-radius: 999px;
  background: linear-gradient(90deg, #3182f6, #22c55e);
`;

const missionFooterStyle = css`
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  font-weight: 900;
  color: #8a5a00;
`;

const stormPanelStyle = (active: boolean) => css`
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-radius: 16px;
  padding: 12px 14px;
  margin-bottom: 16px;
  color: #ffffff;
  background: ${active
    ? 'linear-gradient(135deg, #0f172a, #1d4ed8)'
    : 'linear-gradient(135deg, #334155, #64748b)'};
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.16);
`;

const stormTitleStyle = css`
  font-size: 13px;
  font-weight: 900;
`;

const stormDescStyle = css`
  margin-top: 3px;
  font-size: 11px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.72);
`;

const stormBadgeStyle = css`
  flex-shrink: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  padding: 7px 10px;
  font-size: 11px;
  font-weight: 900;
  white-space: nowrap;
`;

const tierRewardPanelStyle = css`
  background: #ffffff;
  border: 1px solid ${adaptive.grey200};
  border-radius: 14px;
  padding: 12px;
  margin-bottom: 16px;
  box-shadow: 0 8px 20px rgba(49, 64, 84, 0.06);
`;

const tierRewardHeaderStyle = css`
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 10px;
`;

const tierRewardTitleStyle = css`
  font-size: 13px;
  font-weight: 800;
  color: ${adaptive.grey900};
`;

const tierRewardBadgeStyle = css`
  flex-shrink: 0;
  border-radius: 999px;
  background: ${adaptive.blue500};
  color: #ffffff;
  padding: 5px 9px;
  font-size: 11px;
  font-weight: 800;
`;

const tierRewardTrackStyle = css`
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;

  @media (max-width: 420px) {
    grid-template-columns: repeat(2, 1fr);
  }
`;

const tierRewardStepStyle = (unlocked: boolean) => css`
  border-radius: 10px;
  padding: 9px;
  background: ${unlocked ? '#eef8f1' : adaptive.greyBackground};
  border: 1px solid ${unlocked ? '#67c587' : adaptive.grey200};
`;

const tierRewardStepNameStyle = css`
  font-size: 11px;
  font-weight: 900;
  color: ${adaptive.grey900};
  margin-bottom: 5px;
`;

const tierRewardStepTextStyle = css`
  font-size: 10px;
  line-height: 1.35;
  font-weight: 700;
  color: ${adaptive.grey500};
`;

const tierRewardProgressStyle = css`
  height: 5px;
  border-radius: 999px;
  background: ${adaptive.grey200};
  overflow: hidden;
  margin-top: 7px;
`;

const tierRewardProgressFillStyle = (ratio: number, unlocked: boolean) => css`
  height: 100%;
  width: ${(Math.min(1, Math.max(0, ratio)) * 100).toFixed(1)}%;
  border-radius: 999px;
  background: ${unlocked ? '#22c55e' : adaptive.blue500};
`;

const scenePulse = keyframes`
  0%, 100% { transform: scale(1); opacity: 0.75; }
  50% { transform: scale(1.08); opacity: 1; }
`;

const driftMote = keyframes`
  0% { transform: translateY(18px) scale(0.7); opacity: 0; }
  20% { opacity: 0.85; }
  100% { transform: translateY(-84px) scale(1); opacity: 0; }
`;

const laneFlow = keyframes`
  0% { background-position: 0 0; }
  100% { background-position: 44px 0; }
`;

const sceneStyle = css`
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(circle at 18% 22%, rgba(255, 176, 64, 0.18), transparent 26%),
    radial-gradient(circle at 82% 18%, rgba(49, 130, 246, 0.16), transparent 26%),
    linear-gradient(135deg, #ffffff, #f3f7fb 62%, #fff8ed);
  border: 1px solid ${adaptive.grey200};
  border-radius: 16px;
  padding: 16px;
  margin-bottom: 16px;
  box-shadow: 0 12px 28px rgba(49, 64, 84, 0.08);
`;

const sceneHeaderStyle = css`
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 14px;
`;

const sceneTitleStyle = css`
  font-size: 15px;
  font-weight: 800;
  color: ${adaptive.grey900};
`;

const sceneSubtitleStyle = css`
  margin-top: 3px;
  font-size: 11px;
  font-weight: 600;
  color: ${adaptive.grey500};
`;

const sceneStatusStyle = css`
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  border-radius: 999px;
  background: rgba(25, 25, 25, 0.72);
  color: #ffffff;
  padding: 6px 10px;
  font-size: 11px;
  font-weight: 700;
`;

const statusDotStyle = css`
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #30d158;
  box-shadow: 0 0 0 4px rgba(48, 209, 88, 0.18);
  animation: ${scenePulse} 1.4s ease-in-out infinite;
`;

const sceneBodyStyle = css`
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 116px;
  gap: 12px;

  @media (max-width: 420px) {
    grid-template-columns: 1fr;
  }
`;

const producerGridStyle = css`
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
`;

const producerLaneStyle = (color: string, active: boolean, ready = false) => css`
  position: relative;
  overflow: hidden;
  min-height: 98px;
  background: rgba(255, 255, 255, 0.76);
  border: 1px solid ${ready ? '#22c55e' : active ? color : adaptive.grey200};
  border-radius: 12px;
  padding: 10px;
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 8px;
  align-items: center;
  cursor: ${ready ? 'pointer' : 'default'};
  box-shadow: ${ready ? '0 0 0 3px rgba(34, 197, 94, 0.14)' : 'none'};

  &::after {
    content: '';
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: 8px;
    height: 4px;
    border-radius: 999px;
    background-image: linear-gradient(
      90deg,
      ${color} 0 18px,
      rgba(255, 255, 255, 0.25) 18px 28px
    );
    background-size: 44px 4px;
    opacity: ${ready ? 0.85 : active ? 0.55 : 0.2};
    animation: ${laneFlow} 1.1s linear infinite;
  }

  &:active {
    transform: ${ready ? 'scale(0.98)' : 'none'};
  }
`;

const producerSpriteStyle = (active: boolean) => css`
  width: 42px;
  height: 42px;
  filter: drop-shadow(0 5px 8px rgba(0, 0, 0, 0.1));
  animation: ${active ? `${scenePulse} 1.8s ease-in-out infinite` : 'none'};
`;

const idleYawnKeyframes = keyframes`
  0%, 70%, 100% { transform: translateY(0) scale(1); opacity: 1; }
  78% { transform: translateY(-1.5px) scale(1.04, 0.96); opacity: 0.94; }
  88% { transform: translateY(-2.5px) scale(1.06, 0.94); opacity: 0.88; }
  96% { transform: translateY(-0.5px) scale(1.02, 0.99); opacity: 0.97; }
`;

const idleSpriteWrapperStyle = (mood: Mood) => css`
  display: inline-block;
  width: 100%;
  height: 100%;
  animation: ${mood === 'idle' ? css`${idleYawnKeyframes} 8s ease-in-out infinite` : 'none'};
`;

const producerInfoStyle = css`
  min-width: 0;
`;

const producerNameStyle = css`
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  font-size: 12px;
  font-weight: 800;
  color: ${adaptive.grey900};
`;

const producerRateStyle = css`
  margin-top: 3px;
  font-size: 10px;
  font-weight: 700;
  color: ${adaptive.grey500};
`;

const producerTrackStyle = css`
  height: 6px;
  background: ${adaptive.grey200};
  border-radius: 999px;
  overflow: hidden;
  margin-top: 8px;
`;

const producerFillStyle = (ratio: number, color: string) => css`
  height: 100%;
  width: ${(Math.min(1, Math.max(0, ratio)) * 100).toFixed(1)}%;
  background: ${color};
  border-radius: 999px;
  transition: width 0.25s ease;
`;

const producerNextStyle = css`
  margin-top: 5px;
  font-size: 10px;
  font-weight: 700;
  color: ${adaptive.blue500};
`;

const activityPanelStyle = css`
  min-height: 100%;
  background: rgba(255, 255, 255, 0.68);
  border: 1px solid rgba(255, 255, 255, 0.78);
  border-radius: 12px;
  padding: 10px;
`;

const activityTitleStyle = css`
  font-size: 11px;
  font-weight: 800;
  color: ${adaptive.grey700};
  margin-bottom: 8px;
`;

const activityListStyle = css`
  display: flex;
  flex-direction: column;
  gap: 6px;
`;

const activityItemStyle = css`
  font-size: 10px;
  line-height: 1.3;
  font-weight: 700;
  color: ${adaptive.grey700};
  background: rgba(255, 255, 255, 0.72);
  border-radius: 8px;
  padding: 6px 7px;
`;

const activityEmptyStyle = css`
  font-size: 10px;
  line-height: 1.4;
  color: ${adaptive.grey400};
`;

const moteStyle = (left: number, delay: number, color: string) => css`
  position: absolute;
  left: ${left}%;
  bottom: 4px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: ${color};
  opacity: 0;
  filter: blur(0.1px);
  animation: ${driftMote} 3.2s ${delay}s ease-in-out infinite;
`;

const idleInfoStyle = css`
  background: ${adaptive.greyBackground};
  border-radius: 12px;
  padding: 12px 16px;
  margin-bottom: 20px;
  display: flex;
  gap: 16px;
`;

const idleStatStyle = css`
  display: flex;
  flex-direction: column;
  gap: 2px;
`;

const idleLabelStyle = css`
  font-size: 11px;
  color: ${adaptive.grey500};
`;

const idleValueStyle = css`
  font-size: 13px;
  font-weight: 700;
  color: ${adaptive.blue500};
`;

const boostPanelStyle = css`
  background: #0f172a;
  border-radius: 14px;
  padding: 12px;
  margin-bottom: 20px;
  color: #ffffff;
`;

const boostPanelHeaderStyle = css`
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
`;

const boostPanelTitleStyle = css`
  font-size: 13px;
  font-weight: 900;
`;

const boostPanelCountStyle = css`
  font-size: 11px;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.62);
`;

const boostListStyle = css`
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 8px;
`;

const boostChipStyle = css`
  display: flex;
  flex-direction: column;
  gap: 4px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 9px 10px;
`;

const boostChipNameStyle = css`
  font-size: 12px;
  line-height: 1.25;
  font-weight: 900;
`;

const boostChipDescStyle = css`
  font-size: 10px;
  line-height: 1.35;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.62);
`;

const boostEmptyStyle = css`
  color: rgba(255, 255, 255, 0.56);
  font-size: 12px;
  font-weight: 700;
`;

const tierSectionStyle = css`
  margin-bottom: 20px;
`;

const tierLabelStyle = css`
  font-size: 12px;
  font-weight: 600;
  color: ${adaptive.grey500};
  text-transform: uppercase;
  letter-spacing: 0;
  margin-bottom: 10px;
`;

const elementGridStyle = css`
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: 12px;
`;

const elementCardBaseStyle = `
  display: flex;
  flex-direction: column;
  align-items: center;
  border-radius: 999px;
  padding: 10px 6px 12px;
  gap: 5px;
  position: relative;
`;

const obtainedCardStyle = css`
  ${elementCardBaseStyle}
  min-height: 104px;
  justify-content: center;
  background:
    radial-gradient(circle at 50% 34%, rgba(255, 255, 255, 0.95), rgba(246, 248, 251, 0.82) 58%, rgba(232, 238, 247, 0.88));
  border: 1px solid rgba(49, 130, 246, 0.18);
  box-shadow:
    inset 0 1px 8px rgba(255, 255, 255, 0.9),
    0 8px 18px rgba(49, 64, 84, 0.08);
  cursor: pointer;
  &:active {
    transform: scale(0.96);
  }
`;

const lockedCardStyle = css`
  ${elementCardBaseStyle}
  background: ${adaptive.greyBackground};
  border: 1.5px solid ${adaptive.grey200};
  opacity: 0.75;
  cursor: default;
`;

const undiscoveredCardStyle = css`
  ${elementCardBaseStyle}
  background: ${adaptive.greyBackground};
  border: 1.5px dashed ${adaptive.grey300};
  opacity: 0.4;
  cursor: default;
  justify-content: center;
  min-height: 80px;
`;

const spriteWrapStyle = css`
  width: 52px;
  height: 52px;
  flex-shrink: 0;
`;

const elementNameStyle = css`
  font-size: 10px;
  font-weight: 600;
  color: ${adaptive.grey900};
  text-align: center;
  line-height: 1.2;
`;

const undiscoveredNameStyle = css`
  font-size: 10px;
  color: ${adaptive.grey400};
  text-align: center;
`;

const elementCountStyle = css`
  font-size: 11px;
  color: ${adaptive.blue500};
  font-weight: 700;
`;

const lockIconStyle = css`
  position: absolute;
  top: 4px;
  right: 4px;
  font-size: 10px;
`;

const spawnRateStyle = css`
  font-size: 9px;
  color: ${adaptive.grey400};
`;

const discoveryPanelStyle = css`
  background: #101828;
  border-radius: 16px;
  padding: 14px;
  color: #ffffff;
  margin-bottom: 20px;
`;

const discoveryHeaderStyle = css`
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
`;

const discoveryTitleStyle = css`
  font-size: 14px;
  font-weight: 800;
`;

const discoveryCountStyle = css`
  font-size: 11px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.65);
`;

const recipeTargetGridStyle = css`
  display: flex;
  flex-direction: column;
  gap: 8px;
`;

const recipeTargetStyle = css`
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 10px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  padding: 10px 12px;
`;

const recipeFormulaStyle = css`
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 800;
`;

const recipeHintStyle = css`
  margin-top: 3px;
  color: rgba(255, 255, 255, 0.62);
  font-size: 10px;
  font-weight: 600;
`;

const recipeRewardStyle = css`
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 800;
  color: #ffd166;
`;

const collectionHeaderStyle = css`
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 12px;
`;

const collectionTitleStyle = css`
  font-size: 15px;
  font-weight: 800;
  color: ${adaptive.grey900};
`;

const resonanceBadgeStyle = css`
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  color: ${adaptive.grey500};
  font-size: 10px;
  font-weight: 700;
`;

const resonanceValueStyle = css`
  color: ${adaptive.blue500};
  font-size: 12px;
  font-weight: 900;
`;

const emptyTargetStyle = css`
  color: rgba(255, 255, 255, 0.62);
  font-size: 12px;
  line-height: 1.5;
  font-weight: 600;
`;

// ────────────────────────────────────────────────────────────
// 상세 정보 패널
// ────────────────────────────────────────────────────────────

const overlayStyle = css`
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 100;
  display: flex;
  align-items: flex-end;
`;

const detailPanelStyle = css`
  width: 100%;
  background: ${adaptive.background};
  border-radius: 20px 20px 0 0;
  padding: 20px;
  padding-bottom: 32px;
`;

const detailHandleStyle = css`
  width: 36px;
  height: 4px;
  background: ${adaptive.grey300};
  border-radius: 2px;
  margin: 0 auto 16px;
`;

const detailHeaderStyle = css`
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
`;

const detailSpriteStyle = css`
  width: 72px;
  height: 72px;
  flex-shrink: 0;
`;

const detailTitleBlockStyle = css`
  flex: 1;
`;

const detailNameStyle = css`
  font-size: 18px;
  font-weight: 700;
  color: ${adaptive.grey900};
  margin: 0 0 2px;
`;

const detailTierStyle = css`
  font-size: 12px;
  color: ${adaptive.grey500};
`;

const detailGridStyle = css`
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 16px;
`;

const detailStatCardStyle = css`
  background: ${adaptive.greyBackground};
  border-radius: 12px;
  padding: 10px 12px;
`;

const detailStatLabelStyle = css`
  font-size: 11px;
  color: ${adaptive.grey500};
  margin-bottom: 4px;
`;

const detailStatValueStyle = css`
  font-size: 15px;
  font-weight: 700;
  color: ${adaptive.grey900};
`;

const enhanceRowStyle = css`
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: ${adaptive.greyBackground};
  border-radius: 12px;
  padding: 12px 16px;
`;

const enhanceLabelStyle = css`
  font-size: 13px;
  font-weight: 600;
  color: ${adaptive.grey700};
  margin-bottom: 6px;
`;

const enhanceDotRowStyle = css`
  display: flex;
  gap: 5px;
  align-items: center;
`;

const enhanceDotStyle = (filled: boolean) => css`
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: ${filled ? adaptive.blue500 : adaptive.grey300};
`;

const enhanceCostStyle = css`
  font-size: 12px;
  font-weight: 600;
  color: ${adaptive.blue500};
`;

const enhanceMaxStyle = css`
  font-size: 12px;
  color: ${adaptive.grey400};
`;

const detailCountBadgeStyle = css`
  font-size: 14px;
  font-weight: 700;
  color: ${adaptive.blue500};
`;

const loreBoxStyle = css`
  background: #111827;
  color: #ffffff;
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 12px;
`;

const loreTitleStyle = css`
  font-size: 12px;
  font-weight: 900;
  color: rgba(255, 255, 255, 0.7);
  margin-bottom: 5px;
`;

const loreTextStyle = css`
  font-size: 13px;
  line-height: 1.5;
  font-weight: 700;
`;

const genealogyStyle = css`
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 12px;
`;

const genealogyCardStyle = css`
  background: ${adaptive.greyBackground};
  border-radius: 12px;
  padding: 10px 12px;
`;

const genealogyTitleStyle = css`
  font-size: 11px;
  font-weight: 900;
  color: ${adaptive.grey500};
  margin-bottom: 6px;
`;

const genealogyTextStyle = css`
  font-size: 12px;
  line-height: 1.45;
  font-weight: 800;
  color: ${adaptive.grey900};
`;

// ────────────────────────────────────────────────────────────
// Tier labels
// ────────────────────────────────────────────────────────────

const TIER_LABELS: Record<number, string> = {
  1: 'Tier 1 — 기본 원소',
  2: 'Tier 2 — 2차 원소',
  3: 'Tier 3 — 희귀 원소',
  4: 'Tier 4 — 에픽 원소',
  5: 'Tier 5 — 전설 원소',
};

// ────────────────────────────────────────────────────────────
// DetailPanel 컴포넌트
// ────────────────────────────────────────────────────────────

type ElementData = (typeof elementsData)[number];

interface ActivityEntry {
  id: number;
  text: string;
}

interface ActiveBoostSummary {
  id: string;
  name: string;
  desc: string;
  remainingMs: number;
}

function getBoostSummary(boostId: string, remainingMs: number): ActiveBoostSummary | null {
  if (boostId === 'global_spawn_boost') {
    return { id: boostId, name: '전체 생산 x2', desc: '모든 자동 생산 속도 적용 중', remainingMs };
  }
  if (boostId === 'gold_boost') {
    return { id: boostId, name: '골드 수입 x2', desc: '모든 골드 수입 적용 중', remainingMs };
  }
  if (boostId.startsWith('tier_') && boostId.endsWith('_boost')) {
    const tier = boostId.replace('tier_', '').replace('_boost', '');
    return { id: boostId, name: `Tier ${tier} 생산 x2`, desc: `Tier ${tier} 원소 생산 속도 적용 중`, remainingMs };
  }
  if (boostId.endsWith('_boost')) {
    const elementId = boostId.replace('_boost', '');
    const el = elementsData.find((item) => item.id === elementId);
    if (!el) return null;
    return { id: boostId, name: `${el.name} 생산 x2`, desc: `${el.emoji} ${el.name} 원소 생산 속도 적용 중`, remainingMs };
  }
  return null;
}

interface DetailPanelProps {
  el: ElementData;
  count: number;
  level: number;
  onClose: () => void;
}

function DetailPanel({ el, count, level, onClose }: DetailPanelProps) {
  const spawnRate = calcSpawnRate(el.id, level);
  const idleRate = calcEffectiveIdleRate(el.id, level);
  const isMaxLevel = level >= ENHANCE_MAX_LEVEL;
  const nextCost = isMaxLevel ? null : calcEnhanceCost(level);
  const parentRecipe = recipesData.find((recipe) => recipe.result === el.id);
  const childRecipes = recipesData.filter((recipe) => recipe.ingredients.includes(el.id));
  const parentText = parentRecipe
    ? parentRecipe.ingredients
        .map((id) => elementsData.find((item) => item.id === id)?.name ?? id)
        .join(' + ')
    : '태초 원소';
  const childText =
    childRecipes.length > 0
      ? childRecipes
          .slice(0, 3)
          .map((recipe) => elementsData.find((item) => item.id === recipe.result)?.name ?? recipe.result)
          .join(' · ')
      : '최종 계열';

  return (
    <div css={overlayStyle} onClick={onClose}>
      <div css={detailPanelStyle} onClick={(e) => e.stopPropagation()}>
        <div css={detailHandleStyle} />

        <div css={detailHeaderStyle}>
          <div css={detailSpriteStyle}>
            <CharacterSprite
              elementId={el.id}
              elementColor={el.color}
              tier={el.tier}
              size={72}
              state="obtained"
            />
          </div>
          <div css={detailTitleBlockStyle}>
            <p css={detailNameStyle}>{el.name}</p>
            <span css={detailTierStyle}>
              Tier {el.tier} · {el.rarity} · {el.nameEn}
            </span>
          </div>
          <span css={detailCountBadgeStyle}>×{count.toLocaleString()}</span>
        </div>

        <div css={loreBoxStyle}>
          <div css={loreTitleStyle}>도감 기록</div>
          <div css={loreTextStyle}>{el.description}</div>
        </div>

        <div css={genealogyStyle}>
          <div css={genealogyCardStyle}>
            <div css={genealogyTitleStyle}>탄생 계보</div>
            <div css={genealogyTextStyle}>{parentText}</div>
          </div>
          <div css={genealogyCardStyle}>
            <div css={genealogyTitleStyle}>다음 가능성</div>
            <div css={genealogyTextStyle}>{childText}</div>
          </div>
        </div>

        <div css={detailGridStyle}>
          <div css={detailStatCardStyle}>
            <div css={detailStatLabelStyle}>생산 속도</div>
            <div css={detailStatValueStyle}>+{spawnRate.toFixed(3)}/s</div>
          </div>
          <div css={detailStatCardStyle}>
            <div css={detailStatLabelStyle}>골드 수입</div>
            <div css={detailStatValueStyle}>+{idleRate.toFixed(2)}/s</div>
          </div>
          <div css={detailStatCardStyle}>
            <div css={detailStatLabelStyle}>기본 수입률</div>
            <div css={detailStatValueStyle}>{el.idleIncomeRate}/s</div>
          </div>
          <div css={detailStatCardStyle}>
            <div css={detailStatLabelStyle}>보유 수량</div>
            <div css={detailStatValueStyle}>{count.toLocaleString()}</div>
          </div>
        </div>

        <div css={enhanceRowStyle}>
          <div>
            <div css={enhanceLabelStyle}>강화 레벨 Lv.{level}</div>
            <div css={enhanceDotRowStyle}>
              {Array.from({ length: ENHANCE_MAX_LEVEL }, (_, i) => (
                <span key={i} css={enhanceDotStyle(i < level)} />
              ))}
            </div>
          </div>
          {isMaxLevel ? (
            <span css={enhanceMaxStyle}>MAX</span>
          ) : (
            <span css={enhanceCostStyle}>
              다음 강화 💰{formatGold(nextCost!)}
            </span>
          )}
        </div>
      </div>
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// ElementCard (메모이제이션 — count/level 동일하면 리렌더 안 함)
// ────────────────────────────────────────────────────────────

interface ElementCardProps {
  el: ElementData;
  state: ElementState;
  count: number;
  level: number;
  onSelect: (el: ElementData) => void;
  isAutomated?: boolean;
  isTutorialTarget?: boolean;
}

const ElementCard = memo(function ElementCard({
  el,
  state,
  count,
  level,
  onSelect,
  isAutomated = true,
  isTutorialTarget,
}: ElementCardProps) {
  const spawnRate = calcSpawnRate(el.id, level);

  if (state === 'undiscovered') {
    return (
      <div css={undiscoveredCardStyle}>
        <div css={spriteWrapStyle}>
          <CharacterSprite elementId={el.id} elementColor={el.color} tier={el.tier} size={56} state="undiscovered" />
        </div>
        <span css={undiscoveredNameStyle}>???</span>
      </div>
    );
  }

  if (state === 'locked') {
    return (
      <div css={lockedCardStyle}>
        <span css={lockIconStyle}>🔒</span>
        <div css={spriteWrapStyle}>
          <CharacterSprite elementId={el.id} elementColor={el.color} tier={el.tier} size={56} state="locked" />
        </div>
        <span css={elementNameStyle}>{el.name}</span>
      </div>
    );
  }

  return (
    <div
      css={obtainedCardStyle}
      onClick={() => onSelect(el)}
      data-tutorial={isTutorialTarget ? 'elements-first-card' : undefined}
    >
      <div css={spriteWrapStyle}>
        <CharacterSprite elementId={el.id} elementColor={el.color} tier={el.tier} size={56} state="obtained" />
      </div>
      <span css={elementNameStyle}>{el.name}</span>
      <span css={elementCountStyle}>×{count.toLocaleString()}</span>
      <span css={spawnRateStyle}>{isAutomated ? `+${spawnRate.toFixed(2)}/s` : '티어 대기'}</span>
    </div>
  );
});

// ────────────────────────────────────────────────────────────
// ElementsScreen (메인)
// ────────────────────────────────────────────────────────────

export function ElementsScreen() {
  // 전체 store 구독 대신 필요한 slice만 selector로 구독 (불필요한 리렌더 방지)
  const gold = useGameStore((s) => s.gold);
  const elements = useGameStore((s) => s.elements);
  const discoveredElements = useGameStore((s) => s.discoveredElements);
  const elementLevels = useGameStore((s) => s.elementLevels);
  const spawnAccumulators = useGameStore((s) => s.spawnAccumulators);
  const activeBoosts = useGameStore((s) => s.activeBoosts);
  const prestigeGoldMultiplier = useGameStore((s) => s.prestigeGoldMultiplier);
  const prestigeSpawnMultiplier = useGameStore((s) => s.prestigeSpawnMultiplier);
  const permanentGoldMultiplier = useGameStore((s) => s.permanentGoldMultiplier);
  const permanentSpawnMultiplier = useGameStore((s) => s.permanentSpawnMultiplier);
  const dailyProgress = useGameStore((s) => s.dailyProgress);
  const activeStorm = useGameStore((s) => s.activeStorm);
  const claimDailyBonus = useGameStore((s) => s.claimDailyBonus);
  const claimDailyMission = useGameStore((s) => s.claimDailyMission);
  const harvestElement = useGameStore((s) => s.harvestElement);
  const idleMood = useIdleMood();
  const [selectedEl, setSelectedEl] = useState<ElementData | null>(null);
  const [activityLog, setActivityLog] = useState<ActivityEntry[]>([]);
  const { items: floatItems, add: addFloat } = useFloatingItems(1100);
  const prevElements = useRef<Record<string, number>>({});
  const prevGold = useRef<number>(-1);
  const floatCount = useRef<number>(0);
  const activitySeq = useRef<number>(0);

  // 자동 수집 플로팅 이펙트: 원소 수 또는 골드 증가 감지
  useEffect(() => {
    const W = window.innerWidth;
    const H = window.innerHeight;
    let showed = 0;
    const newActivities: ActivityEntry[] = [];

    // 원소 증가 감지 (idle tick에서 발생)
    for (const el of elementsData) {
      const prev = prevElements.current[el.id] ?? -1;
      const curr = elements[el.id] ?? 0;
      if (prev >= 0 && curr > prev) {
        // 최대 2개까지만 표시 (너무 많으면 지저분)
        if (showed < 2) {
          addFloat({
            text: `${el.emoji} +${curr - prev}`,
            x: W * 0.15 + Math.random() * W * 0.7,
            y: H * 0.2 + Math.random() * H * 0.4,
            color: el.color,
            fontSize: 16,
          });
          showed++;
        }
        newActivities.push({
          id: activitySeq.current++,
          text: `${el.emoji} ${el.name} +${curr - prev}`,
        });
      }
    }
    prevElements.current = { ...elements };

    // 골드 증가 감지
    if (prevGold.current >= 0 && gold > prevGold.current) {
      const gained = gold - prevGold.current;
      // 매 3번 tick마다 1번만 표시 (너무 잦지 않게)
      floatCount.current = (floatCount.current + 1) % 3;
      if (floatCount.current === 0) {
        addFloat({
          text: `+${gained} 💰`,
          x: W * 0.3 + Math.random() * W * 0.4,
          y: H * 0.15 + Math.random() * H * 0.15,
          color: '#F7C12A',
          fontSize: 13,
        });
      }
      newActivities.push({
        id: activitySeq.current++,
        text: `💰 골드 +${formatGold(gained)}`,
      });
    }
    prevGold.current = gold;

    if (newActivities.length > 0) {
      setActivityLog((prev) => [...newActivities.reverse(), ...prev].slice(0, 5));
    }
  }, [elements, gold]); // eslint-disable-line react-hooks/exhaustive-deps

  const totalElements = elementsData.length;
  const discoveredElementIds = getDiscoveredElementIds(discoveredElements, elements);
  const tierAutomation = calcTierAutomationStatus(discoveredElementIds);

  const discoveredElementList = elementsData.filter((el) =>
    discoveredElementIds.includes(el.id)
  );

  const autoProducerElements = discoveredElementList.filter(
    (el) => el.tier <= tierAutomation.unlockedTier
  );

  const craftableRecipes = recipesData.filter(
    (recipe) => !discoveredElementIds.includes(recipe.result) && isElementUnlocked(recipe.result, elements)
  );

  const resonance = calcResonanceBonuses(elements);
  const now = Date.now();
  const effectiveSpawnRate = (el: ElementData) => {
    const boostId = el.id + '_boost';
    const boostMultiplier = (activeBoosts[boostId] ?? 0) > now ? 2.0 : 1.0;
    const globalSpawnMultiplier = (activeBoosts.global_spawn_boost ?? 0) > now ? 2.0 : 1.0;
    const tierBoostMultiplier = (activeBoosts[`tier_${el.tier}_boost`] ?? 0) > now ? 2.0 : 1.0;
    const stormMultiplier =
      activeStorm && activeStorm.expiresAt > now && activeStorm.elementId === el.id ? 5.0 : 1.0;
    return (
      calcSpawnRate(el.id, elementLevels[el.id] ?? 0) *
      boostMultiplier *
      globalSpawnMultiplier *
      tierBoostMultiplier *
      stormMultiplier *
      prestigeSpawnMultiplier *
      permanentSpawnMultiplier *
      resonance.spawnMultiplier
    );
  };
  const goldBoostMultiplier = (activeBoosts.gold_boost ?? 0) > now ? 2.0 : 1.0;
  const effectiveGoldRate = (el: ElementData) =>
    calcEffectiveIdleRate(el.id, elementLevels[el.id] ?? 0) *
    goldBoostMultiplier *
    prestigeGoldMultiplier *
    permanentGoldMultiplier *
    resonance.goldMultiplier;

  const totalSpawnPerSec = autoProducerElements.reduce(
    (sum, el) => sum + effectiveSpawnRate(el),
    0
  );

  const totalGoldPerSec = autoProducerElements.reduce(
    (sum, el) => sum + effectiveGoldRate(el),
    0
  );

  const activeProducers = autoProducerElements
    .slice()
    .sort((a, b) => {
      const countDiff = (elements[b.id] ?? 0) - (elements[a.id] ?? 0);
      if (countDiff !== 0) return countDiff;
      return b.tier - a.tier;
    })
    .slice(0, 4);

  const sceneStatus = ['채집 중', '응축 중', '정제 중'][Math.floor(Date.now() / 1000) % 3];
  const moteColors = activeProducers.length > 0
    ? activeProducers.map((el) => el.color)
    : ['#3182F6', '#FFB020', '#00C853'];
  const activeBoostSummaries = Object.entries(activeBoosts)
    .map(([boostId, expiresAt]) => getBoostSummary(boostId, expiresAt - now))
    .filter((summary): summary is ActiveBoostSummary => summary !== null && summary.remainingMs > 0)
    .sort((a, b) => a.remainingMs - b.remainingMs);

  const tierGroups = [1, 2, 3, 4, 5].map((tier) => ({
    tier,
    items: discoveredElementList.filter((el) => el.tier === tier),
  })).filter(({ items }) => items.length > 0);

  // 첫 번째 obtained 원소 ID (튜토리얼 스포트라이트용)
  const firstObtainedId = discoveredElementList[0]?.id ?? null;

  const unlockRatio = discoveredElementList.length / totalElements;
  const dailyBonusGold = 100 + Math.min(6, dailyProgress.streak) * 25;
  const stormElement = activeStorm
    ? elementsData.find((el) => el.id === activeStorm.elementId)
    : null;
  const stormActive = Boolean(activeStorm && activeStorm.expiresAt > now);
  const stormRemainingMs = activeStorm
    ? (stormActive ? activeStorm.expiresAt - now : activeStorm.nextAt - now)
    : 0;

  return (
    <div css={containerStyle}>
      <div css={headerStyle}>
        <h1 css={titleStyle}>원소</h1>
        <div css={goldBadgeStyle}>💰 {gold.toLocaleString()}</div>
      </div>

      {/* 합성 진행 상황 프로그레스 바 */}
      <div css={progressBarWrapStyle}>
        <div css={progressHeaderStyle}>
          <span css={progressLabelStyle}>원소 해금 진행</span>
          <span css={progressCountStyle}>
            {discoveredElementList.length} / {totalElements}
          </span>
        </div>
        <div css={progressTrackStyle}>
          <div css={progressFillStyle(unlockRatio)} />
        </div>
      </div>

      <section css={dailyPanelStyle}>
        <div css={dailyHeaderStyle}>
          <div css={dailyTitleStyle}>오늘의 창조 루틴</div>
          <div css={dailyStreakStyle}>연속 {dailyProgress.streak}일</div>
        </div>
        <div css={dailyBonusRowStyle}>
          <div css={dailyBonusTextStyle}>
            <div css={dailyBonusNameStyle}>데일리 보너스</div>
            <div css={dailyBonusDescStyle}>
              오늘 접속 보상 💰{dailyBonusGold.toLocaleString()}G
            </div>
          </div>
          <button
            css={compactButtonStyle(!dailyProgress.bonusClaimed)}
            onClick={claimDailyBonus}
            disabled={dailyProgress.bonusClaimed}
          >
            {dailyProgress.bonusClaimed ? '수령 완료' : '받기'}
          </button>
        </div>
        <div css={missionListStyle}>
          {DAILY_MISSIONS.map((mission) => {
            const current = getDailyMissionProgress(mission, dailyProgress);
            const done = current >= mission.target;
            const claimed = dailyProgress.claimedMissionIds.includes(mission.id);
            return (
              <div key={mission.id} css={missionCardStyle(done, claimed)}>
                <div css={missionNameStyle}>{mission.title}</div>
                <div css={missionDescStyle}>{mission.description}</div>
                <div css={missionProgressStyle}>
                  <div css={missionProgressFillStyle(current / mission.target)} />
                </div>
                <div css={missionFooterStyle}>
                  <span>
                    {Math.min(current, mission.target).toLocaleString()}/{mission.target.toLocaleString()}
                    {' · '}
                    💰{mission.rewardGold}
                  </span>
                  <button
                    css={compactButtonStyle(done && !claimed)}
                    onClick={() => claimDailyMission(mission.id)}
                    disabled={!done || claimed}
                  >
                    {claimed ? '완료' : '수령'}
                  </button>
                </div>
              </div>
            );
          })}
        </div>
      </section>

      {activeStorm && stormElement && (
        <section css={stormPanelStyle(stormActive)}>
          <div>
            <div css={stormTitleStyle}>
              {stormActive ? 'Element Storm 진행 중' : '다음 Element Storm'}
            </div>
            <div css={stormDescStyle}>
              {stormElement.emoji} {stormElement.name}
              {stormActive ? ' 생산 속도 x5' : ' 폭풍 예보'}
            </div>
          </div>
          <div css={stormBadgeStyle}>
            {stormActive ? '남은 시간 ' : '시작까지 '}
            {formatRemaining(stormRemainingMs)}
          </div>
        </section>
      )}

      <section css={tierRewardPanelStyle}>
        <div css={tierRewardHeaderStyle}>
          <div css={tierRewardTitleStyle}>자동 생산 티어 보상</div>
          <div css={tierRewardBadgeStyle}>T{tierAutomation.unlockedTier} 생산 중</div>
        </div>
        <div css={tierRewardTrackStyle}>
          {TIER_AUTOMATION_GOALS.map((goal) => {
            const current = countDiscoveredByTier(discoveredElementIds, goal.requiredTier);
            const unlocked = tierAutomation.unlockedTier >= goal.tier;
            const ratio = current / goal.requiredCount;

            return (
              <div key={goal.tier} css={tierRewardStepStyle(unlocked)}>
                <div css={tierRewardStepNameStyle}>
                  {unlocked ? '해금됨' : `목표 T${goal.tier}`}
                </div>
                <div css={tierRewardStepTextStyle}>
                  T{goal.requiredTier} 발견 {Math.min(current, goal.requiredCount)}/{goal.requiredCount}
                  {' · '}
                  보상 {goal.rewardGold}G
                </div>
                <div css={tierRewardProgressStyle}>
                  <div css={tierRewardProgressFillStyle(ratio, unlocked)} />
                </div>
              </div>
            );
          })}
        </div>
      </section>

      <section css={sceneStyle} aria-label="자동 생산 현장">
        {moteColors.slice(0, 4).map((color, i) => (
          <span key={`${color}-${i}`} css={moteStyle(16 + i * 22, i * 0.45, color)} />
        ))}
        <div css={sceneHeaderStyle}>
          <div>
            <div css={sceneTitleStyle}>원소 작업장</div>
            <div css={sceneSubtitleStyle}>
              T{tierAutomation.unlockedTier} 이하 발견 원소 {autoProducerElements.length}종이 생성됩니다
            </div>
          </div>
          <div css={sceneStatusStyle}>
            <span css={statusDotStyle} />
            <span>{sceneStatus}</span>
          </div>
        </div>

        <div css={sceneBodyStyle}>
          <div css={producerGridStyle}>
            {activeProducers.map((el) => {
              const rate = effectiveSpawnRate(el);
              const progress = spawnAccumulators[el.id] ?? 0;
              const nextSec = rate > 0 ? (1 - progress) / rate : Infinity;
              const active = rate > 0;
              const harvestReady = active && progress >= 0.75;

              return (
                <div
                  key={el.id}
                  css={producerLaneStyle(el.color, active, harvestReady)}
                  onClick={() => {
                    if (!harvestReady) return;
                    const result = harvestElement(el.id);
                    if (!result.success) return;
                    addFloat({
                      text: `${el.emoji} +${result.count} 수확`,
                      x: window.innerWidth * 0.5,
                      y: window.innerHeight * 0.28,
                      color: el.color,
                      fontSize: 16,
                    });
                    setActivityLog((prev) => [
                      {
                        id: activitySeq.current++,
                        text: `${el.emoji} ${el.name} 직접 수확 +${result.count}`,
                      },
                      ...prev,
                    ].slice(0, 5));
                  }}
                >
                  <div css={producerSpriteStyle(active)}>
                    <div css={idleSpriteWrapperStyle(idleMood)}>
                      <CharacterSprite
                        elementId={el.id}
                        elementColor={el.color}
                        tier={el.tier}
                        size={42}
                        state={(elements[el.id] ?? 0) > 0 ? 'obtained' : 'locked'}
                      />
                    </div>
                  </div>
                  <div css={producerInfoStyle}>
                    <div css={producerNameStyle}>
                      <span>{el.name}</span>
                      <span>×{formatGold(elements[el.id] ?? 0)}</span>
                    </div>
                    <div css={producerRateStyle}>+{rate.toFixed(2)}/s</div>
                    <div css={producerTrackStyle}>
                      <div css={producerFillStyle(progress, el.color)} />
                    </div>
                    <div css={producerNextStyle}>
                      {harvestReady ? '탭해서 보너스 수확' : `다음 생성 ${formatSeconds(nextSec)}`}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>

          <aside css={activityPanelStyle}>
            <div css={activityTitleStyle}>최근 획득</div>
            {activityLog.length > 0 ? (
              <div css={activityListStyle}>
                {activityLog.map((entry) => (
                  <div key={entry.id} css={activityItemStyle}>
                    {entry.text}
                  </div>
                ))}
              </div>
            ) : (
              <div css={activityEmptyStyle}>잠시 후 생산 기록이 표시됩니다.</div>
            )}
          </aside>
        </div>
      </section>

      {/* 방치 수입 요약 */}
      <div css={idleInfoStyle}>
        <div css={idleStatStyle}>
          <span css={idleLabelStyle}>원소 수집</span>
          <span css={idleValueStyle}>+{totalSpawnPerSec.toFixed(2)}/s</span>
        </div>
        <div css={idleStatStyle}>
          <span css={idleLabelStyle}>골드 수입</span>
          <span css={idleValueStyle}>+{totalGoldPerSec.toFixed(1)}/s</span>
        </div>
        <div css={idleStatStyle}>
          <span css={idleLabelStyle}>발견 가능</span>
          <span css={idleValueStyle}>{craftableRecipes.length}종</span>
        </div>
      </div>

      <section css={boostPanelStyle}>
        <div css={boostPanelHeaderStyle}>
          <div css={boostPanelTitleStyle}>상점 효과 적용 현황</div>
          <div css={boostPanelCountStyle}>{activeBoostSummaries.length}개 활성</div>
        </div>
        {activeBoostSummaries.length > 0 ? (
          <div css={boostListStyle}>
            {activeBoostSummaries.map((boost) => (
              <div key={boost.id} css={boostChipStyle}>
                <div css={boostChipNameStyle}>
                  {boost.name} · {formatBoostTime(boost.remainingMs)}
                </div>
                <div css={boostChipDescStyle}>{boost.desc}</div>
              </div>
            ))}
          </div>
        ) : (
          <div css={boostEmptyStyle}>상점에서 구매한 시간제 효과가 여기에 표시됩니다.</div>
        )}
      </section>

      <section css={discoveryPanelStyle}>
        <div css={discoveryHeaderStyle}>
          <div css={discoveryTitleStyle}>다음 발견 목표</div>
          <div css={discoveryCountStyle}>{craftableRecipes.length}개 조합 가능</div>
        </div>
        {craftableRecipes.length > 0 ? (
          <div css={recipeTargetGridStyle}>
            {craftableRecipes.slice(0, 4).map((recipe) => {
              const left = elementsData.find((el) => el.id === recipe.ingredients[0]);
              const right = elementsData.find((el) => el.id === recipe.ingredients[1]);
              const result = elementsData.find((el) => el.id === recipe.result);
              if (!left || !right || !result) return null;

              return (
                <div key={recipe.id} css={recipeTargetStyle}>
                  <div>
                    <div css={recipeFormulaStyle}>
                      <span>{left.emoji}</span>
                      <span>+</span>
                      <span>{right.emoji}</span>
                      <span>→</span>
                      <span>{result.emoji}</span>
                      <span>{result.name}</span>
                    </div>
                    <div css={recipeHintStyle}>
                      합성하면 작업장에 새 생산원이 추가됩니다
                    </div>
                  </div>
                  <div css={recipeRewardStyle}>+{recipe.tier * 10}G</div>
                </div>
              );
            })}
          </div>
        ) : (
          <div css={emptyTargetStyle}>
            보유 원소를 더 모으거나 합성 화면에서 새 조합을 찾아보세요.
          </div>
        )}
      </section>

      <div css={collectionHeaderStyle}>
        <div css={collectionTitleStyle}>보유 원소 궤도</div>
        <div css={resonanceBadgeStyle}>
          <span>상위 원소 공명</span>
          <span css={resonanceValueStyle}>
            생산 x{resonance.spawnMultiplier.toFixed(2)} · 골드 x{resonance.goldMultiplier.toFixed(2)}
          </span>
        </div>
      </div>

      {/* 티어별 보유 원소 */}
      {tierGroups.map(({ tier, items }) => (
        <div key={tier} css={tierSectionStyle}>
          <div css={tierLabelStyle}>{TIER_LABELS[tier]}</div>
          <div css={elementGridStyle}>
            {items.map((el) => (
              <ElementCard
                key={el.id}
                el={el}
                state="obtained"
                count={elements[el.id] ?? 0}
                level={elementLevels[el.id] ?? 0}
                onSelect={setSelectedEl}
                isAutomated={el.tier <= tierAutomation.unlockedTier}
                isTutorialTarget={el.id === firstObtainedId}
              />
            ))}
          </div>
        </div>
      ))}

      {/* 원소 상세 정보 패널 */}
      {selectedEl !== null && (
        <DetailPanel
          el={selectedEl}
          count={elements[selectedEl.id] ?? 0}
          level={elementLevels[selectedEl.id] ?? 0}
          onClose={() => setSelectedEl(null)}
        />
      )}

      {/* 자동 수집 플로팅 이펙트 */}
      <FloatingOverlay items={floatItems} />
    </div>
  );
}
