# backend/app/seed.py
import json
from datetime import date

from sqlmodel import Session, select

from .db import engine, init_db
from .models import (
    ApiToken,
    Approval,
    ApprovalLog,
    ApprovalSource,
    ApprovalStatus,
    AuditLog,
    AuthSession,
    AutomationRule,
    AutomationRunLog,
    AutomationStats,
    AutomationSuggestion,
    AutonomyLevel,
    AutonomySetting,
    Briefing,
    Calendar,
    CalEvent,
    ChatMessage,
    ClsType,
    ConnectorAccount,
    ConnectorAccountLog,
    ConnectorSource,
    ConnectorSyncState,
    Digest,
    Draft,
    Email,
    ErrandStep,
    ErrandTask,
    Event,
    ExternalLink,
    FinanceBudget,
    FinanceCategory,
    FinanceInsight,
    FinanceSub,
    FinanceTx,
    FocusBlock,
    Folder,
    Goal,
    HealthHabit,
    HealthRing,
    HealthSample,
    HealthVital,
    InboxClassification,
    InboxItem,
    InboxKind,
    InboxStatus,
    JourneyLink,
    KnowledgeCollection,
    KnowledgeItem,
    MailAccount,
    MailFolder,
    Meeting,
    MeetingAction,
    Notification,
    NotificationGuard,
    NotifyStats,
    OAuthState,
    Person,
    Prio,
    ProactiveCard,
    Project,
    RagChunk,
    ResearchChart,
    ResearchCollection,
    ResearchQA,
    ResearchReport,
    ResearchSource,
    SavedTrip,
    SenderRule,
    Sent,
    SleepNight,
    Sphere,
    Task,
    TaskComment,
    TaskStatus,
    Trip,
    TripChecklist,
    TripDay,
    TripPlan,
    TripPrep,
    TripRoute,
    TripStay,
    UserCredential,
    WeeklyReview,
)
from .seed_mail import _seed_mail, _seed_notify

YEAR = 2026

# 원본 journey-clean-data.js links[] — HEX→tone 키 변환 (from, to, tone, dash)
JOURNEY_LINKS = [
    ("m-brief", "t-report", "blue", False),
    ("t-report", "k-strat", "coral", False),
    ("t-wire", "k-design", "violet", False),
    ("t-interview", "k-11", "green", True),
    ("t-welcome", "k-stand", "green", True),
    ("k-strat", "w-focus", "ink", False),
    ("k-design", "w-retro", "violet", True),
    ("k-11", "w-next", "green", True),
]


def _seed_journey(s: Session) -> None:
    for i, (frm, to, tone, dash) in enumerate(JOURNEY_LINKS, start=1):
        s.add(
            JourneyLink(id=f"jl{i}", from_node=frm, to_node=to, tone=tone, dash=dash, sort_order=i)
        )


def D(mmdd: str | None):
    """'06-08' -> date(2026,6,8). 빈값/None -> None"""
    if not mmdd:
        return None
    m, d = mmdd.split("-")
    return date(YEAR, int(m), int(d))


# ---- people (REF/assets/tasks-data.js people) ----
PEOPLE = [
    ("jiwoo", "지우", "지", "var(--blue)", True),
    ("hyunwoo", "현우", "현", "var(--violet)", False),
    ("minseo", "민서", "민", "var(--green)", False),
    ("jaeho", "재호", "재", "var(--coral)", False),
    ("sua", "수아", "수", "oklch(0.66 0.13 200)", False),
]

# ---- folders + projects (REF tree) ----
FOLDERS = [
    ("work", "업무", "ink", "folder", 0),
    ("life", "개인", "blue", "heart", 1),
]
# (id, folder_id, parent_id, name, tone, sort)
PROJECTS = [
    # 업무
    ("biz", "work", None, "경영 전략", "coral", 0),
    ("biz-okr", "work", "biz", "2026 Q2 OKR", "coral", 0),
    ("biz-report", "work", "biz", "분기 리포트", "coral", 1),
    ("biz-budget", "work", "biz", "예산 관리", "coral", 2),
    ("onb", "work", None, "온보딩 리디자인", "violet", 1),
    ("onb-research", "work", "onb", "사용자 리서치", "violet", 0),
    ("onb-wire", "work", "onb", "와이어프레임", "violet", 1),
    ("onb-voice", "work", "onb", "음성 인터페이스", "violet", 2),
    ("team", "work", None, "팀 운영", "green", 2),
    ("team-hr", "work", "team", "채용 & 온보딩", "green", 0),
    ("team-retro", "work", "team", "회고", "green", 1),
    # 개인
    ("me", "life", None, "일상", "blue", 0),
    ("life-trip", "life", None, "여행 — 한국", "coral", 1),
    ("life-fam", "life", None, "가족", "green", 2),
]

# ---- tasks (REF tasks; 중첩) ----
TASKS = [
    {
        "id": "k1",
        "title": "분기 리포트 초안 마무리",
        "project": "biz-report",
        "assignee": "jiwoo",
        "due": "06-08",
        "prio": "높음",
        "status": "doing",
        "notes": "<h3>목표</h3><p>경영진 미팅용 Q2 성과 리포트. <b>리텐션·매출·예산</b> 세 섹션으로 구성한다.</p><blockquote>핵심 지표는 시각화해서 한눈에 들어오게.</blockquote>",
        "comments": [
            {"who": "hyunwoo", "text": "매출 섹션은 제가 오늘 안으로 넘겨드릴게요."},
            {"who": "jiwoo", "text": "좋아요, 예산 섹션만 확정되면 취합할게요."},
        ],
        "children": [
            {
                "title": "리텐션 데이터 취합",
                "status": "done",
                "assignee": "sua",
                "due": "06-08",
                "project": "biz-report",
                "children": [
                    {
                        "title": "코호트 정의 확정",
                        "status": "done",
                        "assignee": "sua",
                        "due": "06-07",
                    },
                    {
                        "title": "주차별 잔존율 추출",
                        "status": "done",
                        "assignee": "sua",
                        "due": "06-08",
                    },
                    {
                        "title": "이탈 사유 태깅",
                        "status": "done",
                        "assignee": "jaeho",
                        "due": "06-08",
                        "children": [
                            {"title": "인터뷰 발췌 5건", "status": "done", "assignee": "jaeho"},
                            {"title": "사유 카테고리 분류", "status": "done", "assignee": "jaeho"},
                        ],
                    },
                ],
            },
            {
                "title": "매출 섹션 작성",
                "status": "doing",
                "assignee": "jiwoo",
                "due": "06-09",
                "prio": "높음",
                "project": "biz-report",
                "notes": "<p>MRR/ARR 표는 완료. 증감 코멘트 마무리 필요.</p>",
                "children": [
                    {"title": "MRR / ARR 표 정리", "status": "done", "assignee": "jiwoo"},
                    {"title": "전분기 대비 증감 코멘트", "status": "doing", "assignee": "jiwoo"},
                    {"title": "예측 시나리오 3종", "status": "todo", "assignee": "jiwoo"},
                ],
            },
            {
                "title": "예산 섹션 작성",
                "status": "todo",
                "assignee": "jiwoo",
                "due": "06-10",
                "project": "biz-budget",
            },
            {
                "title": "경영진 검토 요청 메일",
                "status": "todo",
                "assignee": "jiwoo",
                "due": "06-10",
                "project": "biz-report",
            },
        ],
    },
    {
        "id": "k2",
        "title": "온보딩 와이어프레임 피드백 정리",
        "project": "onb-wire",
        "assignee": "hyunwoo",
        "due": "06-09",
        "prio": "높음",
        "status": "review",
        "notes": "<p>디자인 리뷰에서 나온 3개 화면 수정사항을 취합하고 우선순위를 매긴다.</p>",
        "comments": [{"who": "sua", "text": "3번 화면 CTA 위치는 아래로 내리는 게 좋겠어요."}],
        "children": [
            {
                "title": "환영 화면 수정안",
                "status": "done",
                "assignee": "hyunwoo",
                "project": "onb-wire",
                "children": [
                    {"title": "카피 톤 조정", "status": "done", "assignee": "hyunwoo"},
                    {"title": "일러스트 교체 요청", "status": "doing", "assignee": "minseo"},
                ],
            },
            {"title": "권한 요청 화면 재배치", "status": "doing", "assignee": "hyunwoo"},
            {"title": "음성 안내 추가 검토", "status": "todo", "assignee": "sua"},
        ],
    },
    {
        "id": "k5",
        "title": "사용자 인터뷰 5건 정리",
        "project": "onb-research",
        "assignee": "sua",
        "due": "06-10",
        "prio": "보통",
        "status": "doing",
        "children": [
            {"title": "녹취 요약 (5건)", "status": "doing", "assignee": "sua"},
            {"title": "인사이트 태깅", "status": "todo", "assignee": "sua"},
            {"title": "리서치 보드 업데이트", "status": "todo", "assignee": "minseo"},
        ],
    },
    {
        "id": "k6",
        "title": "OKR 중간 점검 자료 준비",
        "project": "biz-okr",
        "assignee": "jiwoo",
        "due": "06-11",
        "prio": "높음",
        "status": "todo",
        "children": [
            {"title": "Objective별 진척도 집계", "status": "todo", "assignee": "jiwoo"},
            {"title": "리스크 항목 표시", "status": "todo", "assignee": "jiwoo"},
        ],
    },
    {
        "id": "k4",
        "title": "구독 결제 카드 갱신",
        "project": "me",
        "assignee": "jiwoo",
        "due": "06-12",
        "prio": "보통",
        "status": "todo",
        "children": [],
    },
    {
        "id": "k3",
        "title": "신규 입사자 환영 메일 발송",
        "project": "team-hr",
        "assignee": "minseo",
        "due": "06-07",
        "prio": "보통",
        "status": "done",
        "children": [
            {"title": "메일 템플릿 작성", "status": "done", "assignee": "minseo"},
            {"title": "수신자 명단 확인", "status": "done", "assignee": "minseo"},
        ],
    },
    {
        "id": "k13",
        "title": "스프린트 회고 문서 배포",
        "project": "team-retro",
        "assignee": "minseo",
        "due": "06-08",
        "prio": "낮음",
        "status": "review",
        "children": [
            {"title": "액션 아이템 담당자 지정", "status": "done", "assignee": "minseo"},
            {"title": "다음 스프린트 반영 확인", "status": "doing", "assignee": "jaeho"},
        ],
    },
    {
        "id": "k10",
        "title": "모바일 푸시 알림 QA",
        "project": "onb-wire",
        "assignee": "sua",
        "due": "06-09",
        "prio": "높음",
        "status": "doing",
        "children": [
            {"title": "iOS 시나리오 3종", "status": "done", "assignee": "sua"},
            {"title": "Android 시나리오 3종", "status": "doing", "assignee": "sua"},
            {"title": "딥링크 라우팅 확인", "status": "todo", "assignee": "jaeho"},
        ],
    },
    {
        "id": "k14",
        "title": "데이터 전처리 파이프라인",
        "project": "onb-research",
        "assignee": "minseo",
        "due": "06-10",
        "prio": "보통",
        "status": "waiting",
        "delegated": True,
        "notes": "<p>일정이 빠듯해 같은 프로젝트의 <b>민서님</b>께 위임 — 현재 완료를 기다리는 중입니다.</p>",
        "children": [
            {"title": "원천 데이터 스키마 정리", "status": "done", "assignee": "minseo"},
            {"title": "결측치 처리 규칙 정의", "status": "doing", "assignee": "minseo"},
            {"title": "정제 스크립트 작성", "status": "todo", "assignee": "minseo"},
        ],
    },
    {
        "id": "k20",
        "title": "한국행 비행기 티켓 구매",
        "project": "life-trip",
        "assignee": "jiwoo",
        "due": "06-14",
        "prio": "높음",
        "status": "todo",
        "notes": "<p>스마트 인박스에서 자동 생성된 작업이에요. 아리가 <b>가격 추적 알림</b>을 켜뒀고, 적정가가 보이면 결재함으로 알려드려요.</p>",
        "children": [
            {
                "title": "날짜 후보 확정",
                "status": "doing",
                "assignee": "jiwoo",
                "project": "life-trip",
            },
            {
                "title": "가격 알림 확인 후 결제",
                "status": "todo",
                "assignee": "jiwoo",
                "project": "life-trip",
            },
        ],
    },
    {
        "id": "k21",
        "title": "엄마 생신 선물 알아보기",
        "project": "life-fam",
        "assignee": "jiwoo",
        "due": "06-20",
        "prio": "보통",
        "status": "todo",
        "children": [],
    },
]

# kx 카운터 (원본 tuid 와 동일하게 kx1,kx2,...)
_kx = 0


def kx() -> str:
    global _kx
    _kx += 1
    return f"kx{_kx}"


# 댓글 TEXT PK 카운터 (c1, c2, ...)
_cidx = 0


def cid() -> str:
    global _cidx
    _cidx += 1
    return f"c{_cidx}"


def insert_task(s: Session, node: dict, parent_id: str | None, project_id: str, order: int):
    tid = node.get("id") or kx()
    pid = node.get("project") or project_id  # 상속 규칙
    t = Task(
        id=tid,
        project_id=pid,
        parent_id=parent_id,
        title=node["title"],
        status=TaskStatus(node.get("status", "todo")),
        assignee_id=node.get("assignee", "jiwoo"),
        due=D(node.get("due")),
        prio=Prio(node.get("prio", "보통")),
        notes=node.get("notes", ""),
        est=node.get("est", ""),
        delegated=node.get("delegated", False),
        sort_order=order,
    )
    s.add(t)
    for c in node.get("comments", []):
        s.add(TaskComment(id=cid(), task_id=tid, person_id=c["who"], text=c["text"]))
    for i, child in enumerate(node.get("children", [])):
        insert_task(s, child, tid, pid, i)


# ---- inbox (REF sinbox-data.js) ----
INBOX = [
    {
        "id": "s1",
        "kind": "text",
        "status": "new",
        "raw": "다음 주에 한국 놀러가는 비행기 티켓 사기",
        "cls": {
            "type": "task",
            "sphere": "life",
            "proj_label": "개인 › 여행 — 한국",
            "project_id": "life-trip",
            "tone": "coral",
            "due_text": "출발 전 · ~6/14",
            "when_text": "오늘 21:00 빈 시간 추천",
            "extra": "가격 추적 알림 켜둠",
            "reason": "구매라는 행동이 있으니 '작업' 맞아요. 작업 트리의 '개인' 아래에 '여행 — 한국' 프로젝트를 만들어 넣었어요 — 따로 섹션이 생기는 게 아니라 다른 작업과 똑같이 보여요. 출발까지 일주일이라 가격 알림도 걸어뒀어요.",
            "confidence": 0.92,
        },
    },
    {
        "id": "s2",
        "kind": "text",
        "status": "confirmed",
        "raw": "수요일 11시 자전거 수리 맡기기",
        "cls": {
            "type": "event",
            "sphere": "life",
            "proj_label": "개인 캘린더",
            "project_id": None,
            "tone": "blue",
            "due_text": "수 6/10 11:00",
            "when_text": "캘린더 등록 완료",
            "extra": "",
            "reason": "시간이 정해진 일은 작업이 아니라 일정으로 바로 등록해요.",
            "confidence": 0.95,
        },
    },
    {
        "id": "s3",
        "kind": "voice",
        "status": "confirmed",
        "raw": "음성 메모 0:09 — 엄마 생신 선물 미리 알아보기",
        "cls": {
            "type": "task",
            "sphere": "life",
            "proj_label": "가족",
            "project_id": "life-fam",
            "tone": "green",
            "due_text": "6/20 전",
            "when_text": "주말 오전 블록",
            "extra": "",
            "reason": "기한이 느슨한 개인 작업이라 주말 블록에 배치했어요.",
            "confidence": 0.8,
        },
    },
    {
        "id": "s4",
        "kind": "text",
        "status": "confirmed",
        "raw": "온보딩 환영 화면에 짧은 애니메이션 넣으면 어떨까",
        "cls": {
            "type": "idea",
            "sphere": "work",
            "proj_label": "온보딩 리디자인 · 아이디어 보드",
            "project_id": "onb",
            "tone": "violet",
            "due_text": "",
            "when_text": "",
            "extra": "",
            "reason": "아직 행동이 정해지지 않아 보드에 보관 — 목요일 디자인 싱크 안건으로도 제안해둘게요.",
            "confidence": 0.7,
        },
    },
]

# ---- dashboard 읽기전용 (REF data.js / approve-data.js) ----
# (id, time, title, tag, dur, tone키, soon)
SCHEDULE = [
    ("e1", "09:30", "팀 데일리 스탠드업", "프로덕트", "15분", "blue", False),
    ("e2", "11:00", "디자인 리뷰 — 온보딩 플로우", "디자인", "45분", "violet", False),
    ("e3", "14:00", "분기 전략 미팅", "경영진", "60분", "coral", True),
    ("e4", "16:30", "1:1 — 민서님", "팀", "30분", "green", False),
]
# (id, title, pct, sub, tone키)
GOALS = [
    ("g1", "분기 OKR — 사용자 리텐션", 68, "12개 중 8개 달성", "blue"),
    ("g2", "주 4회 운동", 75, "이번 주 3/4회", "coral"),
    ("g3", "‘딥 워크’ 책 완독", 40, "320쪽 중 128쪽", "violet"),
]
APPROVALS = [
    (
        "a1",
        "cal",
        "coral",
        "low",
        "07:42",
        "치과 예약을 16:00로 옮겼어요",
        "14시 분기 전략 미팅과 겹침 · 병원 예약 시스템에서 빈 슬롯 확인 후 변경",
        "",
        "",
        "원래 시간으로",
    ),
    (
        "a2",
        "mail",
        "blue",
        "low",
        "06:10",
        "영수증·뉴스레터 7통을 정리했어요",
        "영수증 3통 → 금융 폴더 · 뉴스레터 4통 → 읽을거리, 받은편지함은 중요한 것만 남김",
        "",
        "",
        "되돌리기",
    ),
    (
        "a3",
        "cal",
        "violet",
        "low",
        "07:40",
        "내일 오전 딥 워크 2시간을 예약했어요",
        "분기 리포트 마감(내일 18시) 대비 · 9:00–11:00, 방해 금지로 설정",
        "",
        "",
        "블록 해제",
    ),
    (
        "a4",
        "mail",
        "violet",
        "high",
        "보내기 대기",
        "현우님께 회신 초안이 준비됐어요",
        "“잘 받았어요! 금요일 오전까지 화면별 코멘트 정리해서 드릴게요.”",
        "보내기",
        "수정",
        "",
    ),
    (
        "a5",
        "users",
        "green",
        "high",
        "전달 대기",
        "민서님께 ‘데이터 전처리’ 위임 요청",
        "오늘 일정 과부하 감지 · 맥락 요약과 마감(목)을 담은 요청 메시지 작성 완료",
        "전달",
        "내가 할게",
        "",
    ),
    (
        "a6",
        "wallet",
        "amber",
        "high",
        "확인 필요",
        "Netflix 일시정지를 추천해요",
        "최근 2개월 시청 기록 없음 · 모레 17,000원 결제 예정 — 정지 절차는 준비해뒀어요",
        "일시정지",
        "유지",
        "",
    ),
]
BRIEFING = dict(
    today="6월 7일 일요일",
    weather_temp=24,
    weather_cond="맑음 · 한낮 28°",
    weather_icon="cloudSun",
    commute="출근 23분 · 평소보다 4분 빠름",
    sleep="어젯밤 7시간 12분 · 평소만큼 푹 잤어요",
    note="오늘은 오후 미팅이 핵심이에요. 오전을 비워 <b>분기 리포트</b>에 집중하시면 좋겠어요. 14시 전엔 비가 그칠 예정이라 우산은 안 챙기셔도 돼요.",
    saved_today="47분",
    today_routed=7,
)


def _seed_dashboard(s: Session) -> None:
    """대시보드 읽기전용 시드 — run_seed 내부에서만 호출하는 헬퍼.
    Approval 시드는 phase-7 _seed_approvals 로 단일화(중복 적재 금지)."""
    for i, (eid, t, title, tag, dur, tone, soon) in enumerate(SCHEDULE):
        s.add(
            Event(id=eid, time=t, title=title, tag=tag, dur=dur, tone=tone, soon=soon, sort_order=i)
        )
    for i, (gid, title, pct, sub, tone) in enumerate(GOALS):
        s.add(Goal(id=gid, title=title, pct=pct, sub=sub, tone=tone, sort_order=i))
    s.add(Briefing(id=1, **BRIEFING))  # 단일 row id=1


# ---- 결재함 (REF approve-data.js) ----
# (time, text) — REF approve-data.js log
APPROVAL_LOG = [
    ("08:55", "스탠드업 직전 — 어제 진행 요약 노트 생성"),
    ("07:30", "출근 경로 확인 · 평소보다 4분 빠른 경로로 안내 예약"),
    ("06:00", "구독 결제 캘린더 동기화 (Netflix·Spotify 6/9)"),
    ("어제 23:10", "수면 모드 — 알림 음소거 · 내일 브리핑 예약"),
]
# source 매핑(icon 기반): cal→calendar, mail→mail, users→system, wallet→finance
SRC = {
    "cal": ApprovalSource.calendar,
    "mail": ApprovalSource.mail,
    "users": ApprovalSource.system,
    "wallet": ApprovalSource.finance,
}


def _seed_approvals(s: Session) -> None:
    for i, (aid, icon, tone, risk, time, title, detail, cta, alt, undo) in enumerate(APPROVALS):
        # 시드 status 는 pending; 페이지 응답은 derive_queue 가 자율성으로 재파생.
        s.add(
            Approval(
                id=aid,
                icon=icon,
                tone=tone,
                risk=risk,
                time=time,
                title=title,
                detail=detail,
                cta=cta,
                alt=alt,
                undo_label=undo,
                sort_order=i,
                status=ApprovalStatus.pending.value,
                source=SRC.get(icon, ApprovalSource.system).value,
            )
        )
    for i, (time, text) in enumerate(APPROVAL_LOG):
        s.add(ApprovalLog(id=f"alog{i + 1}", time=time, text=text, sort_order=i))
    s.add(AutonomySetting(id="default", level=AutonomyLevel.mixed.value))  # 기본 '혼합', 단일 row


# ---- 자동화 (REF auto-data.js) ----
# (id, on, cat, name, trigger, cond, action, last, runs)
RULES = [
    (
        "r1",
        True,
        "mail",
        "수아님 메일은 바로",
        "수아님 발신 메일",
        None,
        "즉시 알림 + 3줄 요약",
        "오늘 09:12",
        9,
    ),
    (
        "r2",
        True,
        "focus",
        "딥 워크 보호막",
        "집중 모드 시작",
        "긴급 표시가 아니면",
        "알림 보류 + 메신저 상태 '집중'",
        "오늘 10:00",
        5,
    ),
    (
        "r3",
        True,
        "cal",
        "30분 빈틈 채우기",
        "일정 사이 30분 빈틈",
        "이동이 없으면",
        "가벼운 할 일 자동 배치",
        "어제 15:40",
        7,
    ),
    (
        "r4",
        True,
        "mail",
        "뉴스레터는 저녁에",
        "뉴스레터 도착",
        None,
        "보관 후 저녁 다이제스트로 묶음",
        "어제 18:30",
        14,
    ),
    (
        "r5",
        True,
        "life",
        "영수증 자동 정리",
        "카드 결제 알림",
        None,
        "지출 기록 + 카테고리 분류",
        "오늘 12:48",
        11,
    ),
    (
        "r6",
        False,
        "cal",
        "금요일 오후 비우기",
        "금 13:00 이후 회의 초대",
        "내가 필수 참석자가 아니면",
        "다음 주 시간 제안",
        "지난주 금",
        2,
    ),
    (
        "r7",
        True,
        "life",
        "수면 모드 연동",
        "23:00이 되면",
        "내일 첫 일정이 9시 전이면",
        "수면 모드 제안 + 기상 알람 조정",
        "어제 23:00",
        6,
    ),
]
# (id, pattern, offer:{name,cat,trigger,cond,action})
SUGGESTS = [
    (
        "s1",
        "월요일 아침마다 주간 리포트 초안을 직접 만드시네요. 최근 4주 연속이에요.",
        "주간 리포트 미리 준비",
        "focus",
        "일요일 21:00",
        None,
        "지난주 작업·일정으로 초안 생성",
    ),
    (
        "s2",
        "18시 이후 도착한 메일은 다음 날 아침에 읽으세요. 이번 주 밤 알림만 14번 울렸어요.",
        "퇴근 후 메일은 아침에",
        "mail",
        "18:00~08:00 메일 도착",
        "VIP가 아니면",
        "아침 브리핑으로 묶음",
    ),
]
# (time, rule, text) — REF auto-data.js log
RUN_LOG = [
    ("12:48", "영수증 자동 정리", "점심 결제 13,500원 → 식비로 분류"),
    ("10:00", "딥 워크 보호막", "알림 4건 보류 — 16:00에 묶음 전달 예정"),
    ("09:12", "수아님 메일은 바로", "분기 리포트 피드백 도착 → 요약과 함께 알림"),
    ("08:55", "30분 빈틈 채우기", "10:30 빈틈에 '온보딩 문구 검토' 배치"),
    ("어제 18:30", "뉴스레터는 저녁에", "뉴스레터 5통 → 저녁 다이제스트로 묶음"),
    ("어제 23:00", "수면 모드 연동", "내일 8:30 첫 회의 → 수면 모드 제안"),
]


def _seed_automation(s: Session) -> None:
    rule_by_name = {}
    for rid, on, cat, name, trig, cond, action, last, runs in RULES:
        s.add(
            AutomationRule(
                id=rid,
                name=name,
                cat=cat,
                trigger=trig,
                cond=cond,
                action=action,
                on=on,
                last=last,
                runs=runs,
                fresh=False,
                source="user",
            )
        )
        rule_by_name[name] = rid
    for sid, pat, oname, ocat, otrig, ocond, oaction in SUGGESTS:
        s.add(
            AutomationSuggestion(
                id="asug-" + sid,
                pattern=pat,
                offer_name=oname,
                offer_cat=ocat,
                offer_trigger=otrig,
                offer_cond=ocond,
                offer_action=oaction,
                status="open",
            )
        )
    for i, (time, rule, text) in enumerate(RUN_LOG):
        s.add(
            AutomationRunLog(
                id=f"arun{i + 1}",
                time=time,
                rule_id=rule_by_name.get(rule),
                rule=rule,
                text=text,
                sort_order=i,
            )
        )
    s.add(AutomationStats(id=1, active=7, runs_week=31, saved="1시간 40분"))


def _seed_proactive(s: Session) -> None:
    s.add(
        ProactiveCard(
            id="pc1",
            kind="schedule",
            icon="cal",
            tone="violet",
            title="내일 미팅 3연속 — 점심 비워뒀어요",
            why="10:00·11:00·13:00 연속, 12시 공백을 보호 블록으로 잡았어요",
            cta="그대로 둘게요",
            action_kind="focus_block",
            action_payload=json.dumps(
                {
                    "day": 9,
                    "start": "12:00",
                    "end": "13:00",
                    "type": "light",
                    "title": "점심·재충전 보호",
                },
                ensure_ascii=False,
            ),
            detected_at="방금",
            status="active",
        )
    )
    s.add(
        ProactiveCard(
            id="pc2",
            kind="finance",
            icon="wallet",
            tone="amber",
            title="ChatGPT Plus 청구서가 평소보다 6천원 비싸요",
            why="평소 29,000원 → 이번 35,000원 · 사유 확인 권장",
            cta="자세히",
            action_kind="task",
            action_payload=json.dumps(
                {"title": "ChatGPT Plus 청구 사유 확인", "project_id": "me"}, ensure_ascii=False
            ),
            detected_at="방금",
            status="active",
        )
    )


def _seed_weekly_review(s: Session) -> None:
    patterns = [
        {
            "title": "이번 주 딥워크 8h, 회의 12h",
            "suggest": "화요일 오전을 ‘방해 금지’ 딥워크로 보호할까요?",
            "action_kind": "automation",
            "payload": {
                "name": "화요일 오전 딥워크 보호",
                "cat": "focus",
                "trigger": "매주 화요일 08:00",
                "action": "09:00–11:00 방해 금지 블록 예약",
            },
        }
    ]
    s.add(
        WeeklyReview(
            id="wr-2026-w24",
            week_label="6/7~6/13",
            deep_work_h=8.0,
            meeting_h=12.0,
            done_count=18,
            auto_count=12,
            saved_minutes=196,
            patterns_json=json.dumps(patterns, ensure_ascii=False),
            note="이번 주 딥워크 8h, 회의 12h — 화요일 오전을 ‘방해 금지’ 딥워크로 보호할까요?",
        )
    )


# phase-15: 로그인 자격(AUTH_ENABLED 일 때만 — 데모/CI 회귀 비용 0).
# (user_id, email, role) — 비밀번호는 demo_admin_password 공통(데모).
_USERS = [
    ("jiwoo", "jiwoo@lumi.co", "admin"),
    ("hyunwoo", "hyunwoo@lumi.co", "member"),
]


def _seed_users(s: Session) -> None:
    from .config import get_settings

    if not get_settings().auth_enabled:
        return  # 데모 모드: 자격 미생성(pbkdf2 비용 회피 + current_user 가 지우 우회)
    from .auth.password import hash_password

    pw = get_settings().demo_admin_password
    pw_hash = hash_password(pw)
    for uid, email, role in _USERS:
        s.add(
            UserCredential(
                id=f"uc-{uid}",
                user_id=uid,
                email=email,
                password_hash=pw_hash,
                role=role,
            )
        )


def _reset_counters() -> None:
    global _kx, _cidx
    _kx = 0
    _cidx = 0


def _run(s: Session, reset: bool) -> None:
    """주어진 세션 위에서 시드 적재(트랜잭션 본문)."""
    _reset_counters()
    if reset:
        for tbl in (
            TaskComment,
            Task,
            InboxClassification,
            InboxItem,
            Project,
            Folder,
            Person,
            Event,
            Goal,
            Briefing,
            # phase-7 (FK 자식 먼저)
            ApprovalLog,
            AutomationRunLog,
            Approval,
            AutomationSuggestion,
            AutomationRule,
            AutonomySetting,
            AutomationStats,
            # phase-8 (FK 자식 먼저)
            MeetingAction,
            Meeting,
            FocusBlock,
            CalEvent,
            Calendar,
            # phase-9 (FK 자식 먼저)
            Email,
            Sent,
            Draft,
            MailFolder,
            MailAccount,
            Notification,
            Digest,
            SenderRule,
            NotificationGuard,
            NotifyStats,
            # phase-10 (FK 자식 먼저)
            RagChunk,
            TripPlan,
            SavedTrip,
            TripChecklist,
            TripDay,
            TripPrep,
            TripStay,
            TripRoute,
            Trip,
            ResearchChart,
            ResearchQA,
            ResearchReport,
            ResearchSource,
            ResearchCollection,
            # phase-11 (FK 자식 먼저)
            KnowledgeItem,
            KnowledgeCollection,
            FinanceInsight,
            FinanceSub,
            FinanceCategory,
            FinanceBudget,
            HealthHabit,
            SleepNight,
            HealthVital,
            HealthRing,
            ConnectorSource,
            # phase-12
            JourneyLink,
            # phase-13 (FK 자식 먼저)
            ConnectorAccountLog,
            ConnectorSyncState,
            ExternalLink,
            OAuthState,
            FinanceTx,
            HealthSample,
            ChatMessage,
            ConnectorAccount,
            # phase-14 (FK 자식 먼저: ErrandStep → ErrandTask)
            ErrandStep,
            ErrandTask,
            ProactiveCard,
            WeeklyReview,
            # phase-15 (인증/감사)
            AuthSession,
            ApiToken,
            UserCredential,
            AuditLog,
        ):
            for row in s.exec(select(tbl)).all():
                s.delete(row)
        s.commit()

    for pid, name, ini, color, me in PEOPLE:
        s.add(Person(id=pid, name=name, initial=ini, color=color, is_me=me))
    for fid, name, tone, icon, order in FOLDERS:
        s.add(Folder(id=fid, name=name, tone=tone, icon=icon, sort_order=order))
    for pid, fid, parent, name, tone, order in PROJECTS:
        s.add(
            Project(id=pid, folder_id=fid, parent_id=parent, name=name, tone=tone, sort_order=order)
        )
    s.commit()

    # phase-16+: 작업(Task) mock 시드 제거 — 빈 상태로 시작(앱에서 직접 생성).
    for n, it in enumerate(INBOX, start=1):
        s.add(
            InboxItem(
                id=it["id"],
                kind=InboxKind(it["kind"]),
                raw=it["raw"],
                status=InboxStatus(it["status"]),
            )
        )
        c = it["cls"]
        s.add(
            InboxClassification(
                id=f"cls{n}",  # TEXT PK
                inbox_item_id=it["id"],
                type=ClsType(c["type"]),
                sphere=Sphere(c["sphere"]),
                project_id=c["project_id"],
                proj_label=c["proj_label"],
                tone=c["tone"],
                due_text=c["due_text"],
                when_text=c["when_text"],
                extra=c["extra"],
                reason=c["reason"],
                confidence=c["confidence"],
                model="seed",
            )
        )
    s.commit()

    _seed_dashboard(s)  # 대시보드 읽기전용 시드 통합
    _seed_approvals(s)  # phase-7 결재함
    _seed_automation(s)  # phase-7 자동화
    # phase-16+: 일정(_seed_calendar) mock 시드 제거 — Google 캘린더 연결로 유입.
    _seed_mail(s)  # phase-9 메일 — 연락처(Person)만 유지(메일/계정 mock 제거)
    _seed_notify(s)  # phase-9 알림
    _seed_journey(s)  # phase-12 여정/하루마감
    _seed_proactive(s)  # phase-14 능동 카드 2장
    _seed_weekly_review(s)  # phase-14 주간 리뷰
    _seed_users(s)  # phase-15 로그인 자격(AUTH_ENABLED 일 때만)
    s.commit()


def run_seed(session: Session | None = None, reset: bool = True) -> None:
    """시드 진입 함수 단일 정본.

    - CLI: run_seed()                      → 자체 세션 생성(엔진에서).
    - 테스트: run_seed(session=test_session, reset=True)  → 주어진 세션 재사용.
    """
    init_db()
    if session is not None:
        _run(session, reset)
    else:
        with Session(engine) as s:
            _run(s, reset)


if __name__ == "__main__":
    run_seed()
    print("✅ seed 완료")
