'use client';

import { Suspense, useCallback, useEffect, useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
import { createClient } from '@/lib/supabase/client';
import type { User } from '@supabase/supabase-js';
import TelegramGuideModal from '@/app/components/TelegramGuideModal';
import { KAKAO_OPENCHAT_URL } from '@/lib/contact';
import { findCard } from '@/lib/tarot/cards';
import {
  REQUEST_STATUS,
  TIMELINE_STEPS,
  timelineIndex,
  isRequestStatus,
  type RequestStatus,
} from '@/lib/request-status';

// 마이페이지 — 4탭 재구성 (프로필 / 내 의뢰 / 내 제품 / 주문 내역).
// PublicShell(TopNav)이 상단 내비·로그아웃을 제공하므로 여기서는 콘텐츠만 렌더한다.
// 디자인은 메인(/)·외주(/outsourcing) 페이지의 --jsm-* 토큰·타이포 패턴과 일관되게 구성한다.

const KOR_TIGHT = { letterSpacing: '-0.02em' } as const;
const KOR_BODY = { letterSpacing: '-0.01em' } as const;

type Tab = 'profile' | 'requests' | 'products' | 'orders' | 'ai';
type TelegramLinkState = 'idle' | 'generating' | 'waiting' | 'disconnecting';

// 구 탭 키 → 새 탭 키 매핑. 사주/구독/프로젝트 등 폐지 탭은 프로필로 폴백.
function resolveTab(raw: string | null): Tab {
  switch (raw) {
    case 'requests':
      return 'requests';
    case 'products':
    case 'packs':
      return 'products';
    case 'orders':
    case 'payments':
      return 'orders';
    case 'ai':
      return 'ai';
    case 'profile':
    case 'saju':
    case 'subscription':
    case 'projects':
      return 'profile';
    default:
      return 'requests';
  }
}

// AI 기록 탭 — 타로 리딩 (app/api/tarot/readings 응답)
type TarotReadingRow = {
  id: string;
  category: string | null;
  question: string | null;
  cards: { position: string; card_id?: string; reversed?: boolean }[];
  interpretation: { summary?: string; advice?: string; warning?: string | null };
  summary: string | null;
  created_at: string;
};

// AI 기록 탭 — 사주 기록 (saju_records 테이블, 본인 조회)
type SajuRecordRow = {
  id: string;
  saju_data: Record<string, unknown>;
  created_at: string;
  is_paid: boolean;
};

// AI 기록 탭 — 사주·타로 병합 렌더용 판별 유니언
type AiRecordItem =
  | { kind: 'saju'; data: SajuRecordRow }
  | { kind: 'tarot'; data: TarotReadingRow };

interface Payment {
  id: string;
  created_at: string;
  amount: number;
  status: string;
  product_name: string;
}

interface Order {
  id: string;
  created_at: string;
  service: string;
  message: string;
  status: string;
  // 2026-06-12-client-portal 마이그레이션 신규 컬럼 — 미적용 환경에선 undefined
  public_token?: string | null;
  project_type?: string | null;
  budget?: string | null;
  timeline?: string | null;
  updated_at?: string | null;
}

// 구매 제품 자료 그룹 (/api/packs/list-mine 응답)
interface ProductFileItem {
  id: string;
  label: string;
}
interface ProductGroup {
  id: string;
  name: string;
  files: ProductFileItem[];
}

// orders 테이블(결제 단일 소스) — pending 안내용
interface ProductOrder {
  id: string;
  product_id: string | null;
  status: string;
  created_at: string;
}

// 발주·진행 (quotes 기반 — 견적 수락 시 발주서로 전환, /api/projects)
type ProjectMilestone = { quote_id: string; step_number: number; title: string; status: 'pending' | 'in_progress' | 'completed' };
type Project = { id: string; title: string; status: string; total: number; created_at: string; milestones: ProjectMilestone[] };

const QUOTE_STATUS_LABELS: Record<string, string> = {
  sent: '견적 발송', accepted: '발주 확정', in_progress: '진행중', completed: '완료', delivered: '납품 완료',
};
const PROJECT_ORDERED_STATUSES = ['accepted', 'in_progress', 'completed', 'delivered'];

function MyPageContent() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const supabase = createClient();
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);
  const [tab, setTab] = useState<Tab>(() => resolveTab(searchParams.get('tab')));
  const [payments, setPayments] = useState<Payment[]>([]);
  const [orders, setOrders] = useState<Order[]>([]);
  const [productGroups, setProductGroups] = useState<ProductGroup[]>([]);
  const [productOrders, setProductOrders] = useState<ProductOrder[]>([]);
  const [downloading, setDownloading] = useState<string | null>(null);
  // 내 의뢰 탭 — 펼친 카드 id 집합 (기본 접힘)
  const [expandedRequests, setExpandedRequests] = useState<Set<string>>(new Set());

  // 발주·진행 (quotes 기반)
  const [projects, setProjects] = useState<Project[]>([]);
  const [linkCode, setLinkCode] = useState('');
  const [linkMsg, setLinkMsg] = useState<string | null>(null);
  const [linking, setLinking] = useState(false);
  const [showLinkForm, setShowLinkForm] = useState(false);

  // 텔레그램 연동 상태
  const [telegramChatId, setTelegramChatId] = useState<string | null>(null);
  const [telegramLinkState, setTelegramLinkState] = useState<TelegramLinkState>('idle');
  const [telegramDeepLink, setTelegramDeepLink] = useState<string>('');
  const [telegramLinkExpiry, setTelegramLinkExpiry] = useState<string>('');
  const [showTelegramGuide, setShowTelegramGuide] = useState(false);

  // AI 기록 탭 — 타로 리딩 / 사주 기록
  const [tarotReadings, setTarotReadings] = useState<TarotReadingRow[]>([]);
  const [sajuRecords, setSajuRecords] = useState<SajuRecordRow[]>([]);
  const [expandedAiCards, setExpandedAiCards] = useState<Set<string>>(new Set());

  const loadProjects = useCallback(async () => {
    try {
      const res = await fetch('/api/projects');
      if (!res.ok) return;
      const d = await res.json();
      setProjects(d.projects ?? []);
    } catch { /* 미로그인/네트워크 — 무시 */ }
  }, []);

  // 사주·타로 결과 통합 로드 — 둘 다 실패해도 서로 영향 없이 무시(best-effort)
  const loadAiRecords = useCallback(async () => {
    try {
      const tr = await fetch('/api/tarot/readings');
      if (tr.ok) setTarotReadings((await tr.json()).readings ?? []);
    } catch { /* 무시 */ }
    try {
      // 사주: 세션 클라이언트로 본인 saju_records 조회 (result 페이지와 동일 패턴)
      const { data: { user: authUser } } = await supabase.auth.getUser();
      if (authUser) {
        const { data } = await supabase
          .from('saju_records')
          .select('id, saju_data, created_at, is_paid')
          .eq('user_id', authUser.id)
          .order('created_at', { ascending: false });
        setSajuRecords(data ?? []);
      }
    } catch { /* 무시 */ }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    async function init() {
      const { data: { user } } = await supabase.auth.getUser();
      if (!user) {
        router.push('/login');
        return;
      }
      setUser(user);

      // 결제 내역 조회
      const { data: pay } = await supabase
        .from('payments')
        .select('*')
        .eq('user_id', user.id)
        .order('created_at', { ascending: false })
        .limit(20);
      setPayments(pay || []);

      // 의뢰 내역 조회
      const { data: ord } = await supabase
        .from('contact_requests')
        .select('*')
        .eq('user_id', user.id)
        .order('created_at', { ascending: false })
        .limit(20);
      setOrders(ord || []);

      // 텔레그램 chat_id 조회
      const { data: profile } = await supabase
        .from('profiles')
        .select('telegram_chat_id')
        .eq('id', user.id)
        .maybeSingle();
      setTelegramChatId(profile?.telegram_chat_id ?? null);

      // 구매 제품 자료 그룹 조회 (orders paid 단일 소스)
      const filesRes = await fetch('/api/packs/list-mine');
      if (filesRes.ok) {
        const { products } = await filesRes.json();
        setProductGroups(products ?? []);
      }

      // 결제 주문(orders 테이블) 조회 — pending 안내 / 주문 내역 공유
      const { data: prodOrders } = await supabase
        .from('orders')
        .select('id, product_id, status, created_at')
        .eq('user_id', user.id)
        .order('created_at', { ascending: false })
        .limit(50);
      setProductOrders(prodOrders || []);

      // 발주·진행 (quotes 기반) 조회
      await loadProjects();

      // AI 기록(사주·타로) 조회
      await loadAiRecords();

      setLoading(false);
    }
    init();
  }, [loadProjects, loadAiRecords]);

  // ── 텔레그램 연결 ──
  const handleTelegramConnect = async () => {
    setTelegramLinkState('generating');
    try {
      const res = await fetch('/api/telegram/connect', { method: 'POST' });
      if (!res.ok) throw new Error('API_ERROR');
      const data = await res.json();
      setTelegramDeepLink(data.deepLink);
      setTelegramLinkExpiry(new Date(data.expiresAt).toLocaleTimeString('ko-KR', { hour: '2-digit', minute: '2-digit' }));
      setTelegramLinkState('waiting');

      // 15분 후 자동으로 idle 복귀
      setTimeout(() => setTelegramLinkState('idle'), 15 * 60 * 1000);
    } catch {
      setTelegramLinkState('idle');
      alert('연결 코드 발급 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
    }
  };

  // 연결 후 상태 새로고침 (버튼 클릭 시)
  const handleTelegramRefresh = async () => {
    const { data: profile } = await supabase
      .from('profiles')
      .select('telegram_chat_id')
      .eq('id', user!.id)
      .maybeSingle();
    const chatId = profile?.telegram_chat_id ?? null;
    setTelegramChatId(chatId);
    if (chatId) setTelegramLinkState('idle');
  };

  // ── 텔레그램 연결 해제 ──
  const handleTelegramDisconnect = async () => {
    if (!confirm('텔레그램 연결을 해제하시겠습니까?')) return;
    setTelegramLinkState('disconnecting');
    try {
      await fetch('/api/telegram/connect', { method: 'DELETE' });
      setTelegramChatId(null);
      setTelegramDeepLink('');
    } catch {
      alert('연결 해제 중 오류가 발생했습니다.');
    }
    setTelegramLinkState('idle');
  };

  function toggleRequest(id: string) {
    setExpandedRequests((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }

  function toggleAiCard(id: string) {
    setExpandedAiCards((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }

  // 견적서 코드 연결 (공개 견적 페이지에서 발급된 public_token)
  const handleLink = async () => {
    if (!linkCode.trim() || linking) return;
    setLinking(true); setLinkMsg(null);
    try {
      const res = await fetch('/api/projects/link', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token: linkCode.trim() }),
      });
      const d = await res.json();
      if (!res.ok) { setLinkMsg(d.error ?? '연결에 실패했습니다.'); return; }
      setLinkMsg(d.alreadyLinked ? '이미 연결된 견적서입니다.' : '견적서가 연결되었습니다.');
      setLinkCode('');
      await loadProjects();
    } catch { setLinkMsg('연결에 실패했습니다. 다시 시도해주세요.'); }
    finally { setLinking(false); }
  };

  async function handleDownload(fileId: string) {
    setDownloading(fileId);
    try {
      const res = await fetch('/api/packs/sign-link', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ fileId }),
      });
      const data = await res.json();
      if (!res.ok || !data.url) {
        throw new Error(data.error ?? '링크 발급 실패');
      }
      window.location.href = data.url;
    } catch (e) {
      alert(e instanceof Error ? e.message : '다운로드 준비 중 오류가 발생했습니다');
    } finally {
      setDownloading(null);
    }
  }

  if (loading) {
    return (
      <div
        className="min-h-[60vh] flex items-center justify-center"
        style={{ background: 'var(--jsm-bg)' }}
      >
        <div
          className="w-7 h-7 rounded-full animate-spin"
          style={{ border: '2px solid var(--jsm-accent)', borderTopColor: 'transparent' }}
        />
      </div>
    );
  }

  if (!user) return null;

  // 입금 확인 대기 중인 주문 (orders 테이블 pending)
  const pendingOrders = productOrders.filter((o) => o.status === 'pending');

  // AI 기록 탭 — 사주·타로 결과를 created_at 기준 내림차순 병합
  const aiRecords: AiRecordItem[] = [
    ...sajuRecords.map((r): AiRecordItem => ({ kind: 'saju', data: r })),
    ...tarotReadings.map((r): AiRecordItem => ({ kind: 'tarot', data: r })),
  ].sort((a, b) => new Date(b.data.created_at).getTime() - new Date(a.data.created_at).getTime());

  const tabs: { key: Tab; label: string; count?: number }[] = [
    { key: 'profile', label: '프로필' },
    { key: 'requests', label: '발주·진행', count: orders.length || undefined },
    { key: 'products', label: '내 제품', count: productGroups.length || undefined },
    { key: 'orders', label: '주문 내역', count: (orders.length + payments.length) || undefined },
    { key: 'ai', label: 'AI 기록', count: (sajuRecords.length + tarotReadings.length) || undefined },
  ];

  function selectTab(key: Tab) {
    setTab(key);
    const params = new URLSearchParams(searchParams.toString());
    params.set('tab', key);
    router.replace(`/mypage?${params.toString()}`, { scroll: false });
  }

  return (
    <div style={{ background: 'var(--jsm-bg)' }} className="min-h-[calc(100vh-4rem)]">
      {/* 텔레그램 가이드 모달 */}
      {showTelegramGuide && (
        <TelegramGuideModal onClose={() => setShowTelegramGuide(false)} />
      )}

      {/* ─── 페이지 헤더 ─── */}
      <div className="border-b" style={{ borderColor: 'var(--jsm-line)', background: 'var(--jsm-surface)' }}>
        <div className="max-w-5xl mx-auto px-6 lg:px-8 pt-12 pb-6">
          <span
            className="inline-block text-xs font-semibold mb-4 px-2.5 py-1 rounded"
            style={{ color: 'var(--jsm-accent)', background: 'var(--jsm-accent-soft)', ...KOR_BODY }}
          >
            마이페이지
          </span>
          <div className="flex items-center gap-4">
            <div
              aria-hidden="true"
              className="w-12 h-12 rounded-xl flex items-center justify-center text-white text-lg font-bold flex-shrink-0"
              style={{ background: 'var(--jsm-accent)' }}
            >
              {user.email?.[0].toUpperCase()}
            </div>
            <div className="min-w-0">
              <div
                className="font-bold text-lg leading-tight truncate"
                style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}
              >
                {user.email}
              </div>
              <div className="text-xs mt-0.5" style={{ color: 'var(--jsm-ink-faint)' }}>
                가입일 {new Date(user.created_at).toLocaleDateString('ko-KR')}
              </div>
            </div>
          </div>
        </div>

        {/* ─── 탭 바 (상단 가로 탭 · 모바일 스크롤) ─── */}
        <div className="max-w-5xl mx-auto px-6 lg:px-8">
          <div className="flex gap-1 overflow-x-auto scrollbar-hide -mb-px">
            {tabs.map((t) => {
              const active = tab === t.key;
              return (
                <button
                  key={t.key}
                  onClick={() => selectTab(t.key)}
                  className="flex items-center gap-1.5 px-4 py-3 text-sm font-semibold whitespace-nowrap transition-colors duration-150 border-b-2"
                  style={{
                    color: active ? 'var(--jsm-ink)' : 'var(--jsm-ink-soft)',
                    borderColor: active ? 'var(--jsm-accent)' : 'transparent',
                    ...KOR_BODY,
                  }}
                >
                  {t.label}
                  {t.count !== undefined && t.count > 0 && (
                    <span
                      className="text-xs px-1.5 py-0.5 rounded-full font-semibold"
                      style={
                        active
                          ? { background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' }
                          : { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' }
                      }
                    >
                      {t.count}
                    </span>
                  )}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* ─── 탭 콘텐츠 ─── */}
      <div className="px-6 lg:px-8 py-8 max-w-5xl mx-auto">
        {/* ===== 프로필 ===== */}
        {tab === 'profile' && (
          <div className="space-y-5">
            <Card>
              <CardTitle>계정 정보</CardTitle>
              <div className="mt-4">
                <Row label="이메일" value={user.email ?? '-'} />
                <Row
                  label="로그인 방법"
                  value={user.app_metadata?.provider === 'google' ? 'Google' : '이메일'}
                />
                <Row
                  label="가입일"
                  value={new Date(user.created_at).toLocaleDateString('ko-KR', {
                    year: 'numeric',
                    month: 'long',
                    day: 'numeric',
                  })}
                  last
                />
              </div>
            </Card>

            {/* 텔레그램 연동 카드 */}
            <Card>
              <div className="flex items-center gap-2">
                <CardTitle inline>텔레그램 알림 연동</CardTitle>
                <button
                  onClick={() => setShowTelegramGuide(true)}
                  className="w-5 h-5 rounded-full text-xs font-bold flex items-center justify-center transition-colors"
                  style={{ background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-faint)' }}
                  title="연결 방법 보기"
                >
                  ?
                </button>
                <span className="ml-auto text-xs font-normal" style={{ color: 'var(--jsm-ink-faint)' }}>
                  플래티넘 · 다이아 전용
                </span>
              </div>

              <div className="mt-4">
                {telegramChatId ? (
                  /* ── 연결됨 ── */
                  <div className="flex items-center justify-between flex-wrap gap-3">
                    <div className="flex items-center gap-3">
                      <div
                        className="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0 border"
                        style={{ background: 'var(--jsm-accent-soft)', borderColor: 'var(--jsm-line)' }}
                      >
                        <TelegramIcon className="w-5 h-5" style={{ color: 'var(--jsm-accent)' }} />
                      </div>
                      <div>
                        <div
                          className="text-sm font-semibold flex items-center gap-1.5"
                          style={{ color: 'var(--jsm-ink)' }}
                        >
                          연결됨
                          <span className="w-2 h-2 rounded-full inline-block" style={{ background: '#16a34a' }} />
                        </div>
                        <div className="text-xs" style={{ color: 'var(--jsm-ink-soft)' }}>
                          Chat ID: {telegramChatId}
                        </div>
                      </div>
                    </div>
                    <button
                      onClick={handleTelegramDisconnect}
                      disabled={telegramLinkState === 'disconnecting'}
                      className="px-4 py-2 text-xs font-semibold rounded-lg border transition-colors disabled:opacity-50"
                      style={{ color: '#dc2626', borderColor: '#fecaca' }}
                    >
                      {telegramLinkState === 'disconnecting' ? '해제 중...' : '연결 해제'}
                    </button>
                  </div>
                ) : telegramLinkState === 'waiting' ? (
                  /* ── 연결 대기 중 ── */
                  <div className="space-y-4">
                    <div
                      className="rounded-xl p-4 border"
                      style={{ background: 'var(--jsm-surface-alt)', borderColor: 'var(--jsm-line)' }}
                    >
                      <p className="text-sm font-semibold mb-2" style={{ color: 'var(--jsm-ink)' }}>
                        아래 순서로 진행하세요
                      </p>
                      <ol
                        className="text-xs space-y-1 list-decimal list-inside"
                        style={{ color: 'var(--jsm-ink-soft)' }}
                      >
                        <li>아래 버튼을 클릭해 텔레그램 봇을 엽니다</li>
                        <li>텔레그램에서 <strong>시작</strong> 버튼을 누릅니다</li>
                        <li>봇이 &quot;연결 완료&quot; 메시지를 보내면 새로고침을 눌러주세요</li>
                      </ol>
                      <p className="text-xs mt-2" style={{ color: 'var(--jsm-ink-faint)' }}>
                        유효시간: {telegramLinkExpiry}까지
                      </p>
                    </div>
                    <div className="flex gap-2 flex-wrap">
                      <a
                        href={telegramDeepLink}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="inline-flex items-center gap-2 px-5 py-2.5 text-sm font-semibold rounded-lg text-white transition-colors hover:bg-[var(--jsm-accent-hover)]"
                        style={{ background: 'var(--jsm-accent)' }}
                      >
                        <TelegramIcon className="w-4 h-4" />
                        텔레그램 봇 열기
                      </a>
                      <button
                        onClick={handleTelegramRefresh}
                        className="px-4 py-2.5 text-sm font-semibold rounded-lg border transition-colors hover:bg-[var(--jsm-surface-alt)]"
                        style={{ color: 'var(--jsm-ink-soft)', borderColor: 'var(--jsm-line)' }}
                      >
                        연결 확인 새로고침
                      </button>
                      <button
                        onClick={() => setTelegramLinkState('idle')}
                        className="px-4 py-2.5 text-sm rounded-lg transition-colors"
                        style={{ color: 'var(--jsm-ink-faint)' }}
                      >
                        취소
                      </button>
                    </div>
                  </div>
                ) : (
                  /* ── 미연결 ── */
                  <div className="flex items-center justify-between flex-wrap gap-3">
                    <div className="flex items-center gap-3">
                      <div
                        className="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0 border"
                        style={{ background: 'var(--jsm-surface-alt)', borderColor: 'var(--jsm-line)' }}
                      >
                        <TelegramIcon className="w-5 h-5" style={{ color: 'var(--jsm-ink-faint)' }} />
                      </div>
                      <div>
                        <div className="text-sm font-semibold" style={{ color: 'var(--jsm-ink)' }}>
                          연결 안 됨
                        </div>
                        <div className="text-xs" style={{ color: 'var(--jsm-ink-soft)' }}>
                          텔레그램으로 알림을 바로 받아보세요
                        </div>
                      </div>
                    </div>
                    <button
                      onClick={handleTelegramConnect}
                      disabled={telegramLinkState === 'generating'}
                      className="px-5 py-2.5 text-sm font-semibold rounded-lg text-white transition-colors hover:bg-[var(--jsm-accent-hover)] disabled:opacity-60"
                      style={{ background: 'var(--jsm-accent)' }}
                    >
                      {telegramLinkState === 'generating' ? '생성 중...' : '텔레그램 연결하기'}
                    </button>
                  </div>
                )}
              </div>
            </Card>

            {/* 빠른 메뉴 */}
            <Card>
              <CardTitle>빠른 메뉴</CardTitle>
              <div className="mt-4 grid grid-cols-1 sm:grid-cols-3 gap-3">
                <QuickLink href="/outsourcing#contact" title="외주 문의" sub="프로젝트 문의" />
                <QuickLink href="/products" title="소프트웨어 보기" sub="완성 소프트웨어 목록" />
                <QuickLink href="/outsourcing#contact" title="외주 의뢰" sub="맞춤 개발 문의" />
              </div>
            </Card>
          </div>
        )}

        {/* ===== 발주·진행 + 내 의뢰 ===== */}
        {tab === 'requests' && (
          <div>
            {/* 발주·진행 (quotes 기반 — 견적 수락 시 발주서로 전환) */}
            <section className="mb-8">
              <div className="flex items-center justify-between mb-3">
                <h2 className="text-base font-bold" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
                  발주·진행
                </h2>
                <button
                  type="button"
                  onClick={() => setShowLinkForm((v) => !v)}
                  className="text-xs font-semibold transition-colors hover:underline"
                  style={{ color: 'var(--jsm-accent)', ...KOR_BODY }}
                >
                  {showLinkForm ? '닫기' : '견적서 코드 연결'}
                </button>
              </div>

              {showLinkForm && (
                <div
                  className="mb-4 rounded-lg border p-4"
                  style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
                >
                  <div className="flex items-center gap-2">
                    <input
                      type="text"
                      value={linkCode}
                      onChange={(e) => setLinkCode(e.target.value)}
                      placeholder="견적서 코드를 입력하세요"
                      className="flex-1 min-w-0 px-3 py-2 rounded-lg border text-sm"
                      style={{ borderColor: 'var(--jsm-line)', color: 'var(--jsm-ink)' }}
                    />
                    <button
                      type="button"
                      onClick={handleLink}
                      disabled={linking}
                      className="px-4 py-2 rounded-lg text-sm font-semibold text-white transition-colors hover:bg-[var(--jsm-accent-hover)] disabled:opacity-50 flex-shrink-0"
                      style={{ background: 'var(--jsm-accent)' }}
                    >
                      {linking ? '연결중...' : '연결'}
                    </button>
                  </div>
                  {linkMsg && (
                    <p className="text-xs mt-2 break-keep" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
                      {linkMsg}
                    </p>
                  )}
                </div>
              )}

              {projects.length === 0 ? (
                <p className="text-sm break-keep" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
                  진행 중인 발주가 없습니다. 견적서 코드를 입력해 연결하거나 새로 의뢰해 보세요.
                </p>
              ) : (
                <div className="space-y-3">
                  {projects.map((p) => (
                    <ProjectCard key={p.id} project={p} />
                  ))}
                </div>
              )}
            </section>

            {/* 기존 의뢰 카드 리스트 (contact_requests 기반) */}
            {orders.length === 0 ? (
              <EmptyState
                title="의뢰 내역이 없습니다"
                desc="외주 개발·서비스 문의 내역이 여기에 표시됩니다."
                linkHref="/outsourcing#contact"
                linkLabel="외주 문의하기"
              />
            ) : (
              <div className="space-y-3">
                {orders.map((o) => (
                  <RequestCard
                    key={o.id}
                    order={o}
                    expanded={expandedRequests.has(o.id)}
                    onToggle={() => toggleRequest(o.id)}
                  />
                ))}
              </div>
            )}
          </div>
        )}

        {/* ===== 내 제품 (구매한 제품 자료) ===== */}
        {tab === 'products' && (
          <div className="space-y-4">
            {/* 입금 확인 대기 안내 */}
            {pendingOrders.length > 0 && (
              <div
                className="rounded-xl px-4 py-3 border flex items-start gap-3"
                style={{ background: 'var(--jsm-accent-soft)', borderColor: 'var(--jsm-line)' }}
              >
                <span
                  className="text-xs font-semibold px-2 py-0.5 rounded-full flex-shrink-0 mt-0.5"
                  style={{ background: 'var(--jsm-surface)', color: 'var(--jsm-accent)' }}
                >
                  대기중
                </span>
                <div className="text-sm leading-relaxed break-keep" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
                  입금 확인 대기 중인 주문이 {pendingOrders.length}건 있습니다. 입금이 확인되면 자료 다운로드가 활성화됩니다.
                  {' '}
                  <a
                    href={KAKAO_OPENCHAT_URL}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="font-semibold hover:underline"
                    style={{ color: 'var(--jsm-accent)' }}
                  >
                    카톡 오픈채팅 →
                  </a>
                </div>
              </div>
            )}

            {productGroups.length === 0 ? (
              <EmptyState
                title="구매한 제품이 없습니다"
                desc="소프트웨어·자료를 구매하시면 여기서 다운로드할 수 있습니다."
                linkHref="/products"
                linkLabel="소프트웨어 보기"
              />
            ) : (
              productGroups.map((group) => (
                <Card key={group.id}>
                  <div className="flex items-start justify-between gap-3 mb-4">
                    <div className="font-bold text-base break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
                      {group.name}
                    </div>
                  </div>

                  <div className="border-t pt-4" style={{ borderColor: 'var(--jsm-line)' }}>
                    <div className="text-sm font-semibold mb-3" style={{ color: 'var(--jsm-ink)' }}>
                      자료 패키지 ({group.files.length}개)
                    </div>

                    {group.files.length === 0 ? (
                      <p className="text-xs" style={{ color: 'var(--jsm-ink-soft)' }}>
                        자료 준비 중입니다. 카톡 1:1로 문의해주세요.
                      </p>
                    ) : (
                      <>
                        <ul className="space-y-2 mb-3">
                          {group.files.map((f) => (
                            <li key={f.id} className="flex items-center justify-between gap-2 text-sm">
                              <span className="flex-1 break-keep" style={{ color: 'var(--jsm-ink)' }}>
                                {f.label}
                              </span>
                              <button
                                onClick={() => handleDownload(f.id)}
                                disabled={downloading === f.id}
                                className="px-3 py-1.5 rounded-lg text-xs font-semibold text-white transition-colors hover:bg-[var(--jsm-accent-hover)] disabled:opacity-50"
                                style={{ background: 'var(--jsm-accent)' }}
                              >
                                {downloading === f.id ? '준비중...' : '다운로드'}
                              </button>
                            </li>
                          ))}
                        </ul>
                        <p className="text-xs leading-relaxed" style={{ color: 'var(--jsm-ink-soft)' }}>
                          다운로드 링크는 발급 후 4시간 동안 유효합니다.
                        </p>
                      </>
                    )}
                  </div>
                </Card>
              ))
            )}
          </div>
        )}

        {/* ===== 주문 내역 (의뢰 + 결제 완료) ===== */}
        {tab === 'orders' && (
          <div className="space-y-8">
            {/* 주문 목록 (contact_requests) */}
            <section>
              <SectionHeading>주문 목록</SectionHeading>
              {orders.length === 0 ? (
                <EmptyState
                  title="주문 내역이 없습니다"
                  desc="서비스 신청·외주 문의 내역이 여기에 표시됩니다."
                  linkHref="/outsourcing#contact"
                  linkLabel="외주 문의하기"
                />
              ) : (
                <div className="space-y-3">
                  {orders.map((o) => (
                    <Card key={o.id} compact>
                      <div className="flex items-start justify-between gap-3 mb-1.5">
                        <div className="font-bold break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
                          {o.service}
                        </div>
                        <StatusBadge status={o.status} />
                      </div>
                      <p
                        className="text-sm line-clamp-1 break-keep"
                        style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}
                      >
                        {o.message}
                      </p>
                      <div className="text-xs mt-2" style={{ color: 'var(--jsm-ink-faint)' }}>
                        {new Date(o.created_at).toLocaleDateString('ko-KR')}
                      </div>
                    </Card>
                  ))}
                </div>
              )}
            </section>

            {/* 결제 완료 내역 (payments) */}
            <section>
              <SectionHeading>결제 완료 내역</SectionHeading>
              {payments.length === 0 ? (
                <div
                  className="rounded-2xl border px-6 py-8 text-center text-sm"
                  style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)', color: 'var(--jsm-ink-soft)' }}
                >
                  결제 완료된 내역이 아직 없습니다.
                </div>
              ) : (
                <div
                  className="rounded-2xl border overflow-hidden"
                  style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
                >
                  <table className="w-full text-sm">
                    <thead style={{ background: 'var(--jsm-surface-alt)' }}>
                      <tr style={{ borderBottom: '1px solid var(--jsm-line)' }}>
                        <th className="px-5 py-3 text-left font-semibold" style={{ color: 'var(--jsm-ink-soft)' }}>서비스</th>
                        <th className="px-5 py-3 text-left font-semibold" style={{ color: 'var(--jsm-ink-soft)' }}>금액</th>
                        <th className="px-5 py-3 text-left font-semibold" style={{ color: 'var(--jsm-ink-soft)' }}>상태</th>
                        <th className="px-5 py-3 text-left font-semibold" style={{ color: 'var(--jsm-ink-soft)' }}>일시</th>
                      </tr>
                    </thead>
                    <tbody>
                      {payments.map((p) => (
                        <tr key={p.id} style={{ borderTop: '1px solid var(--jsm-line)' }}>
                          <td className="px-5 py-3 font-medium" style={{ color: 'var(--jsm-ink)' }}>{p.product_name}</td>
                          <td className="px-5 py-3" style={{ color: 'var(--jsm-ink)' }}>₩{p.amount?.toLocaleString()}</td>
                          <td className="px-5 py-3">
                            <span
                              className="px-2 py-0.5 rounded-full text-xs font-semibold"
                              style={
                                p.status === 'paid'
                                  ? { background: '#dcfce7', color: '#166534' }
                                  : { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' }
                              }
                            >
                              {p.status === 'paid' ? '결제완료' : p.status}
                            </span>
                          </td>
                          <td className="px-5 py-3 text-xs" style={{ color: 'var(--jsm-ink-faint)' }}>
                            {new Date(p.created_at).toLocaleDateString('ko-KR')}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </section>
          </div>
        )}

        {/* ===== AI 기록 (사주·타로 결과 통합) ===== */}
        {tab === 'ai' && (
          <div>
            {aiRecords.length === 0 ? (
              <div
                className="text-center px-6 py-16 rounded-2xl border"
                style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
              >
                <div className="font-bold text-lg mb-2 break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
                  AI 기록이 없습니다
                </div>
                <div className="text-sm mb-6 break-keep max-w-sm mx-auto" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
                  사주 분석·타로 리딩 결과가 여기에 모아서 표시됩니다.
                </div>
                <div className="flex flex-wrap items-center justify-center gap-3">
                  <Link
                    href="/work/saju"
                    className="inline-flex items-center gap-2 px-6 py-3 rounded-lg font-semibold text-sm text-white transition-colors hover:bg-[var(--jsm-accent-hover)]"
                    style={{ background: 'var(--jsm-accent)' }}
                  >
                    사주 분석 하기 →
                  </Link>
                  <Link
                    href="/tarot"
                    className="inline-flex items-center gap-2 px-6 py-3 rounded-lg font-semibold text-sm transition-colors hover:bg-[var(--jsm-surface-alt)]"
                    style={{ color: 'var(--jsm-ink)', border: '1px solid var(--jsm-line)' }}
                  >
                    타로 리딩 하기 →
                  </Link>
                </div>
              </div>
            ) : (
              <div className="space-y-3">
                {aiRecords.map((item) =>
                  item.kind === 'saju' ? (
                    <SajuAiCard key={`saju-${item.data.id}`} record={item.data} />
                  ) : (
                    <TarotAiCard
                      key={`tarot-${item.data.id}`}
                      reading={item.data}
                      expanded={expandedAiCards.has(item.data.id)}
                      onToggle={() => toggleAiCard(item.data.id)}
                    />
                  )
                )}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

export default function MyPage() {
  return (
    <Suspense
      fallback={
        <div
          className="min-h-[60vh] flex items-center justify-center"
          style={{ background: 'var(--jsm-bg)' }}
        >
          <div
            className="w-7 h-7 rounded-full animate-spin"
            style={{ border: '2px solid var(--jsm-accent)', borderTopColor: 'transparent' }}
          />
        </div>
      }
    >
      <MyPageContent />
    </Suspense>
  );
}

/* ─────────── 공통 프레젠테이션 컴포넌트 ─────────── */

function Card({
  children,
  compact = false,
}: {
  children: React.ReactNode;
  compact?: boolean;
}) {
  return (
    <div
      className={`rounded-2xl border ${compact ? 'p-5' : 'p-6'}`}
      style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
    >
      {children}
    </div>
  );
}

function CardTitle({ children }: { children: React.ReactNode; inline?: boolean }) {
  return (
    <h2 className="font-bold" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
      {children}
    </h2>
  );
}

function SectionHeading({ children }: { children: React.ReactNode }) {
  return (
    <h3
      className="text-xs font-semibold uppercase tracking-wider mb-3"
      style={{ color: 'var(--jsm-accent)' }}
    >
      {children}
    </h3>
  );
}

function Row({ label, value, last = false }: { label: string; value: string; last?: boolean }) {
  return (
    <div
      className="flex items-center justify-between py-3"
      style={last ? undefined : { borderBottom: '1px solid var(--jsm-line)' }}
    >
      <span className="text-sm" style={{ color: 'var(--jsm-ink-soft)' }}>{label}</span>
      <span className="text-sm font-semibold" style={{ color: 'var(--jsm-ink)' }}>{value}</span>
    </div>
  );
}

function QuickLink({ href, title, sub }: { href: string; title: string; sub: string }) {
  return (
    <Link
      href={href}
      className="flex flex-col gap-1 p-4 rounded-xl border transition-colors hover:bg-[var(--jsm-surface-alt)]"
      style={{ borderColor: 'var(--jsm-line)' }}
    >
      <span className="text-sm font-semibold" style={{ color: 'var(--jsm-ink)' }}>{title}</span>
      <span className="text-xs" style={{ color: 'var(--jsm-ink-faint)' }}>{sub}</span>
    </Link>
  );
}

// 상태 뱃지 — REQUEST_STATUS 8종.
// completed=성공 그린(예외 허용) / accepted·quoted·in_progress=accent / pending·reviewing=surface-alt
// on_hold·cancelled=faint. 알 수 없는 값(다른 도메인 status 등)은 원문 라벨+기본 스타일 폴백.
const STATUS_BADGE_STYLE: Record<RequestStatus, React.CSSProperties> = {
  completed: { background: '#dcfce7', color: '#166534' },
  accepted: { background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' },
  in_progress: { background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' },
  quoted: { background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' },
  pending: { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' },
  reviewing: { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' },
  on_hold: { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-faint)' },
  cancelled: { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-faint)' },
};

function StatusBadge({ status }: { status: string }) {
  const known = isRequestStatus(status);
  const label = known ? REQUEST_STATUS[status].label : status;
  const style = known
    ? STATUS_BADGE_STYLE[status]
    : { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' };
  return (
    <span
      className="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap flex-shrink-0"
      style={style}
    >
      {label}
    </span>
  );
}

// 펼침 토글 셰브론
function Chevron({ open }: { open: boolean }) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
      style={{
        transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
        transition: 'transform 0.2s ease',
      }}
    >
      <path d="m6 9 6 6 6-6" />
    </svg>
  );
}

function TimelineCheck() {
  return (
    <svg
      width="11"
      height="11"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="3.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
    >
      <path d="M20 6 9 17l-5-5" />
    </svg>
  );
}

// 컴팩트 가로 미니 타임라인 — track 페이지 타임라인의 축소판.
// 모바일에서는 라벨을 숨기고 도트만 노출(라벨 축약 허용).
function MiniTimeline({ current }: { current: number }) {
  return (
    <ol className="flex items-start">
      {TIMELINE_STEPS.map((step, i) => {
        const isDone = i < current;
        const isCurrent = i === current;
        const isLast = i === TIMELINE_STEPS.length - 1;
        const label = REQUEST_STATUS[step].label;
        return (
          <li key={step} className="flex-1 flex flex-col items-center min-w-0">
            <div className="flex items-center w-full">
              {/* 좌측 연결선 */}
              <span
                className="h-0.5 flex-1"
                style={{
                  background: i === 0 ? 'transparent' : i <= current ? 'var(--jsm-accent)' : 'var(--jsm-line)',
                }}
                aria-hidden
              />
              {/* 마커 */}
              <span
                className="relative z-10 flex items-center justify-center rounded-full shrink-0"
                style={{
                  width: 20,
                  height: 20,
                  background: isDone ? 'var(--jsm-accent)' : 'var(--jsm-surface)',
                  border: isDone || isCurrent ? '2px solid var(--jsm-accent)' : '2px solid var(--jsm-line)',
                  color: isDone ? '#ffffff' : 'transparent',
                  boxShadow: isCurrent ? '0 0 0 3px var(--jsm-accent-soft)' : 'none',
                }}
                aria-hidden
              >
                {isDone ? (
                  <TimelineCheck />
                ) : (
                  <span
                    className="rounded-full"
                    style={{
                      width: 6,
                      height: 6,
                      background: isCurrent ? 'var(--jsm-accent)' : 'var(--jsm-line)',
                    }}
                  />
                )}
              </span>
              {/* 우측 연결선 */}
              <span
                className="h-0.5 flex-1"
                style={{
                  background: isLast ? 'transparent' : i < current ? 'var(--jsm-accent)' : 'var(--jsm-line)',
                }}
                aria-hidden
              />
            </div>
            {/* 라벨 — 모바일 숨김 */}
            <span
              className="hidden sm:block mt-1.5 text-[11px] text-center break-keep"
              style={{
                color: isDone || isCurrent ? 'var(--jsm-ink)' : 'var(--jsm-ink-faint)',
                fontWeight: isCurrent ? 700 : 500,
                ...KOR_BODY,
              }}
            >
              {label}
            </span>
          </li>
        );
      })}
    </ol>
  );
}

// 내 의뢰 카드 — 접힘 기본, 펼치면 타임라인 + 의뢰 정보 + 추적 링크
function RequestCard({
  order,
  expanded,
  onToggle,
}: {
  order: Order;
  expanded: boolean;
  onToggle: () => void;
}) {
  const status: RequestStatus = isRequestStatus(order.status) ? order.status : 'pending';
  const current = timelineIndex(status);

  const info: { label: string; value: string }[] = [];
  if (order.project_type) info.push({ label: '프로젝트 유형', value: order.project_type });
  if (order.budget) info.push({ label: '예산', value: order.budget });
  if (order.timeline) info.push({ label: '희망 일정', value: order.timeline });

  return (
    <Card compact>
      {/* 헤더 — 클릭 토글 */}
      <button
        type="button"
        onClick={onToggle}
        aria-expanded={expanded}
        className="w-full text-left"
      >
        <div className="flex items-start justify-between gap-3 mb-2">
          <div className="font-bold break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
            {order.service}
          </div>
          <div className="flex items-center gap-2 flex-shrink-0">
            <StatusBadge status={order.status} />
            <span style={{ color: 'var(--jsm-ink-faint)' }}>
              <Chevron open={expanded} />
            </span>
          </div>
        </div>
        <p
          className={`text-sm break-keep ${expanded ? '' : 'line-clamp-2'}`}
          style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}
        >
          {order.message}
        </p>
        <div className="text-xs mt-2" style={{ color: 'var(--jsm-ink-faint)' }}>
          {new Date(order.created_at).toLocaleDateString('ko-KR')}
        </div>
      </button>

      {/* 펼침 영역 */}
      {expanded && (
        <div className="mt-4 pt-4 border-t" style={{ borderColor: 'var(--jsm-line)' }}>
          {status === 'cancelled' ? (
            <p className="text-sm break-keep" style={{ color: 'var(--jsm-ink-faint)', ...KOR_BODY }}>
              취소된 의뢰입니다.
            </p>
          ) : (
            <>
              {status === 'on_hold' && (
                <div
                  className="mb-4 rounded-lg px-3 py-2.5"
                  style={{ background: 'var(--jsm-surface-alt)' }}
                >
                  <p className="text-xs break-keep" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
                    현재 보류 중입니다 — 조건 조정이 필요하면 회신 주세요.
                  </p>
                </div>
              )}
              <div className="px-1 py-1">
                <MiniTimeline current={current} />
              </div>
            </>
          )}

          {/* 의뢰 정보 */}
          {info.length > 0 && (
            <dl className="mt-5 grid grid-cols-2 gap-x-6 gap-y-3">
              {info.map((item) => (
                <div key={item.label}>
                  <dt className="text-xs mb-0.5" style={{ color: 'var(--jsm-ink-faint)', ...KOR_BODY }}>
                    {item.label}
                  </dt>
                  <dd
                    className="text-sm font-medium break-keep"
                    style={{ color: 'var(--jsm-ink)', ...KOR_BODY }}
                  >
                    {item.value}
                  </dd>
                </div>
              ))}
            </dl>
          )}

          {/* 상세 추적 페이지 링크 */}
          {order.public_token && (
            <Link
              href={`/track/${order.public_token}`}
              className="mt-5 inline-flex items-center gap-1.5 text-sm font-semibold transition-colors hover:underline"
              style={{ color: 'var(--jsm-accent)', ...KOR_BODY }}
            >
              상세 추적 페이지
              <span aria-hidden>→</span>
            </Link>
          )}
        </div>
      )}
    </Card>
  );
}

// 발주서 뱃지 — accepted 이후 상태(발주 확정~납품 완료)에는 "발주서" 뱃지를 병기한다.
function isProjectOrder(status: string): boolean {
  return PROJECT_ORDERED_STATUSES.includes(status);
}

// 발주·진행 카드 — quotes 기반. 총액 + 마일스톤 타임라인(스텝 순서대로 진행 상태 표시).
function ProjectCard({ project }: { project: Project }) {
  return (
    <Card compact>
      <div className="flex items-start justify-between gap-3 mb-2">
        <div className="font-bold break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
          {project.title}
        </div>
        <div className="flex items-center gap-2 flex-shrink-0">
          {isProjectOrder(project.status) && (
            <span
              className="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap"
              style={{ background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' }}
            >
              발주서
            </span>
          )}
          <span
            className="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap"
            style={{ background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' }}
          >
            {QUOTE_STATUS_LABELS[project.status] ?? project.status}
          </span>
        </div>
      </div>

      <div className="text-sm font-semibold mb-4" style={{ color: 'var(--jsm-ink)', ...KOR_BODY }}>
        {project.total.toLocaleString('ko-KR')}원
      </div>

      {project.milestones.length > 0 && (
        <ol className="space-y-2">
          {project.milestones
            .slice()
            .sort((a, b) => a.step_number - b.step_number)
            .map((m) => {
              const done = m.status === 'completed';
              const active = m.status === 'in_progress';
              return (
                <li key={m.step_number} className="flex items-center gap-3">
                  <span
                    className="flex items-center justify-center rounded-full text-xs font-semibold flex-shrink-0"
                    style={{
                      width: 22,
                      height: 22,
                      background: done ? 'var(--jsm-accent)' : 'var(--jsm-surface)',
                      border: done || active ? '2px solid var(--jsm-accent)' : '2px solid var(--jsm-line)',
                      color: done ? '#ffffff' : active ? 'var(--jsm-accent)' : 'var(--jsm-ink-faint)',
                    }}
                  >
                    {m.step_number}
                  </span>
                  <span
                    className="text-sm break-keep"
                    style={{
                      color: done || active ? 'var(--jsm-ink)' : 'var(--jsm-ink-faint)',
                      fontWeight: active ? 700 : 500,
                      ...KOR_BODY,
                    }}
                  >
                    {m.title}
                  </span>
                </li>
              );
            })}
        </ol>
      )}
    </Card>
  );
}

function EmptyState({
  title,
  desc,
  linkHref,
  linkLabel,
}: {
  title: string;
  desc: string;
  linkHref: string;
  linkLabel: string;
}) {
  return (
    <div
      className="text-center px-6 py-16 rounded-2xl border"
      style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
    >
      <div className="font-bold text-lg mb-2 break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
        {title}
      </div>
      <div className="text-sm mb-6 break-keep max-w-sm mx-auto" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
        {desc}
      </div>
      <Link
        href={linkHref}
        className="inline-flex items-center gap-2 px-6 py-3 rounded-lg font-semibold text-sm text-white transition-colors hover:bg-[var(--jsm-accent-hover)]"
        style={{ background: 'var(--jsm-accent)' }}
      >
        {linkLabel} →
      </Link>
    </div>
  );
}

// saju_data(jsonb)에서 생년월일 요약 문자열 구성 — birth_year/month/day 없으면 안내 문구로 폴백
function formatSajuBirth(data: Record<string, unknown>): string {
  const year = data.birth_year;
  const month = data.birth_month;
  const day = data.birth_day;
  const hour = data.birth_hour;
  const gender = data.gender;
  if (typeof year !== 'number' || typeof month !== 'number' || typeof day !== 'number') {
    return '생년월일 정보 없음';
  }
  const parts = [`${year}.${month}.${day}`];
  if (typeof hour === 'number') parts.push(`${hour}시`);
  if (gender === 'female') parts.push('여성');
  else if (gender === 'male') parts.push('남성');
  return parts.join(' · ');
}

// saju_data → /work/saju/result 쿼리 재구성. calendarType은 saju_data에 없으면 solar 기본값
// (result 페이지는 saju_data 저장 시 이미 양력으로 변환된 birth_year/month/day를 사용하기 때문).
function sajuResultHref(data: Record<string, unknown>): string {
  const year = data.birth_year;
  const month = data.birth_month;
  const day = data.birth_day;
  const hour = data.birth_hour;
  const gender = data.gender;
  if (typeof year !== 'number' || typeof month !== 'number' || typeof day !== 'number') return '/work/saju';
  const calendarType =
    (typeof data.calendarType === 'string' && data.calendarType) ||
    (typeof data.calendar === 'string' && data.calendar) ||
    'solar';
  const params = new URLSearchParams({
    year: String(year),
    month: String(month),
    day: String(day),
    gender: typeof gender === 'string' ? gender : 'male',
    calendarType,
  });
  if (typeof hour === 'number') params.set('hour', String(hour));
  return `/work/saju/result?${params.toString()}`;
}

// AI 기록 — 사주 카드. 날짜 + 생년월일 요약 + 결과 다시 보기 링크.
function SajuAiCard({ record }: { record: SajuRecordRow }) {
  return (
    <Card compact>
      <div className="flex items-center justify-between gap-3 mb-3">
        <span
          className="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap"
          style={{ background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' }}
        >
          사주
        </span>
        <span className="text-xs flex-shrink-0" style={{ color: 'var(--jsm-ink-faint)' }}>
          {new Date(record.created_at).toLocaleDateString('ko-KR')}
        </span>
      </div>

      <div className="text-sm font-semibold mb-3 break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
        {formatSajuBirth(record.saju_data)}
      </div>

      <Link
        href={sajuResultHref(record.saju_data)}
        className="inline-flex items-center gap-1.5 text-sm font-semibold transition-colors hover:underline"
        style={{ color: 'var(--jsm-accent)', ...KOR_BODY }}
      >
        결과 다시 보기
        <span aria-hidden>→</span>
      </Link>
    </Card>
  );
}

// AI 기록 — 타로 카드. 날짜·카테고리·질문·3장 카드명·요약 + 조언/주의 접이식.
function TarotAiCard({
  reading,
  expanded,
  onToggle,
}: {
  reading: TarotReadingRow;
  expanded: boolean;
  onToggle: () => void;
}) {
  const hasDetail = Boolean(reading.interpretation?.advice || reading.interpretation?.warning);

  return (
    <Card compact>
      <div className="flex items-start justify-between gap-3 mb-2">
        <div className="flex flex-wrap items-center gap-2">
          <span
            className="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap"
            style={{ background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' }}
          >
            타로
          </span>
          {reading.category && (
            <span
              className="text-xs font-semibold px-2.5 py-1 rounded-full whitespace-nowrap"
              style={{ background: 'var(--jsm-accent-soft)', color: 'var(--jsm-accent)' }}
            >
              {reading.category}
            </span>
          )}
        </div>
        <span className="text-xs flex-shrink-0" style={{ color: 'var(--jsm-ink-faint)' }}>
          {new Date(reading.created_at).toLocaleDateString('ko-KR')}
        </span>
      </div>

      {reading.question && (
        <p className="text-sm font-semibold mb-2 break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}>
          {reading.question}
        </p>
      )}

      <div className="flex flex-wrap gap-1.5 mb-3">
        {reading.cards.map((c, i) => {
          const card = c.card_id ? findCard(c.card_id) : undefined;
          return (
            <span
              key={`${c.position}-${i}`}
              className="text-xs px-2 py-0.5 rounded-full break-keep"
              style={{ background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-soft)' }}
            >
              {c.position}: {card?.name ?? '알 수 없음'}
              {c.reversed ? ' (역방향)' : ''}
            </span>
          );
        })}
      </div>

      {reading.summary && (
        <p className="text-sm leading-relaxed break-keep" style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}>
          {reading.summary}
        </p>
      )}

      {hasDetail && (
        <>
          <button
            type="button"
            onClick={onToggle}
            aria-expanded={expanded}
            className="mt-3 inline-flex items-center gap-1.5 text-xs font-semibold transition-colors hover:underline"
            style={{ color: 'var(--jsm-accent)', ...KOR_BODY }}
          >
            {expanded ? '조언·주의 접기' : '조언·주의 더보기'}
            <Chevron open={expanded} />
          </button>

          {expanded && (
            <div className="mt-3 pt-3 border-t space-y-2" style={{ borderColor: 'var(--jsm-line)' }}>
              {reading.interpretation?.advice && (
                <p className="text-sm leading-relaxed break-keep" style={{ color: 'var(--jsm-ink)', ...KOR_BODY }}>
                  {reading.interpretation.advice}
                </p>
              )}
              {reading.interpretation?.warning && (
                <p className="text-sm leading-relaxed break-keep" style={{ color: '#b45309', ...KOR_BODY }}>
                  주의 — {reading.interpretation.warning}
                </p>
              )}
            </div>
          )}
        </>
      )}
    </Card>
  );
}

function TelegramIcon({ className, style }: { className?: string; style?: React.CSSProperties }) {
  return (
    <svg className={className} style={style} viewBox="0 0 24 24" fill="currentColor" aria-hidden>
      <path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm5.894 8.221-1.97 9.28c-.145.658-.537.818-1.084.508l-3-2.21-1.447 1.394c-.16.16-.295.295-.605.295l.213-3.053 5.56-5.023c.242-.213-.054-.333-.373-.12L7.17 13.667l-2.95-.924c-.64-.203-.654-.64.136-.954l11.566-4.458c.538-.194 1.006.131.972.89z" />
    </svg>
  );
}
