"""Draft markdown writer for cycle_advancer PoC.

YAML frontmatter 스키마 (cycle_advancer/v1)
-------------------------------------------

::

    ---
    schema: cycle_advancer/v1
    source_task_id: task-2485
    proposed_task_id: task-2486
    classification: MERGE_PENDING_DEPENDENCY
    proposal_only: true
    ready_for_dispatch: false
    chairman_required: false       # 합의 시 false, 충돌 시 true
    conflict_summary: null         # 충돌 시 채움
    generated_at: 2026-05-08T00:00:00Z
    generator: cycle_advancer/v1-mock
    deterministic_seed: cycle_advancer-v1-mock
    ---

본 PoC는 **draft md 파일만** 생성한다. 실제 ``.done`` / ``.escalate`` /
``.fail`` 파일이나 dispatch 호출은 절대 수행하지 않는다.
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from . import DETERMINISTIC_SEED, GENERATOR_ID, SCHEMA_VERSION


@dataclass(frozen=True)
class DraftPayload:
    """draft md를 구성하는 모든 필드.

    Attributes:
        source_task_id: 입력 evidence의 task_id.
        proposed_task_id: cycle_advancer가 제안한 다음 task_id.
        classification: 입력 task의 본질 분류.
        chairman_required: 충돌 시 ``True``.
        conflict_summary: 충돌 사유 (없으면 ``None``).
        generated_at: ISO8601 UTC timestamp (``Z`` 접미사 포함).
        consensus_root_cause: 합의된 root cause 요약 (1단계).
        candidate_root_causes: 마아트/외부 AI 후보 (3개 권장).
        evidence_summary: 입력 evidence 요약 (분류/PR/blocker).
        scope: 제안 범위 한 줄.
        affected_files: 다음 task가 건드릴 파일.
        allowed_resources: 격리 리소스 화이트리스트.
        next_steps: chain 의존 다음 단계 설명.
    """

    source_task_id: str
    proposed_task_id: str
    classification: str
    chairman_required: bool
    conflict_summary: str | None
    generated_at: str
    consensus_root_cause: str
    candidate_root_causes: tuple[str, ...]
    evidence_summary: tuple[str, ...]
    scope: str
    affected_files: tuple[str, ...]
    allowed_resources: tuple[str, ...]
    next_steps: tuple[str, ...]


def _yaml_scalar(value: str | bool | None) -> str:
    """YAML 스칼라 직렬화 (frontmatter 한정, 안전한 케이스만 처리).

    PoC 범위에서 frontmatter에 들어가는 값은 결정적이고 단순하므로
    별도 PyYAML 의존성을 두지 않고 직접 직렬화한다.
    """
    if value is None:
        return "null"
    if isinstance(value, bool):
        return "true" if value else "false"
    # 단순 식별자/timestamp/한글 문자열 — 따옴표 불필요한 경우만 등장.
    return str(value)


def render_draft(payload: DraftPayload) -> str:
    """draft md 본문 문자열을 결정적으로 렌더링한다.

    동일 ``payload`` → 동일 출력 (줄바꿈/공백/순서 모두 고정).

    Args:
        payload: 렌더링할 :class:`DraftPayload`.

    Returns:
        frontmatter + 5개 섹션을 포함한 markdown 본문.
    """
    frontmatter_lines = [
        "---",
        f"schema: {SCHEMA_VERSION}",
        f"source_task_id: {_yaml_scalar(payload.source_task_id)}",
        f"proposed_task_id: {_yaml_scalar(payload.proposed_task_id)}",
        f"classification: {_yaml_scalar(payload.classification)}",
        "proposal_only: true",
        "ready_for_dispatch: false",
        f"chairman_required: {_yaml_scalar(payload.chairman_required)}",
        f"conflict_summary: {_yaml_scalar(payload.conflict_summary)}",
        f"generated_at: {payload.generated_at}",
        f"generator: {GENERATOR_ID}",
        f"deterministic_seed: {DETERMINISTIC_SEED}",
        "---",
    ]

    body_lines: list[str] = [""]

    body_lines.append("## 본 task의 본질")
    body_lines.append("")
    body_lines.append(f"- consensus root cause: {payload.consensus_root_cause}")
    body_lines.append("- mock 후보 (마아트 facts + 외부 AI strategy):")
    for candidate in payload.candidate_root_causes:
        body_lines.append(f"  - {candidate}")
    body_lines.append("")

    body_lines.append("## 입력 evidence 요약")
    body_lines.append("")
    for line in payload.evidence_summary:
        body_lines.append(f"- {line}")
    body_lines.append("")

    body_lines.append("## 제안 범위")
    body_lines.append("")
    body_lines.append(f"- scope: {payload.scope}")
    body_lines.append("- affected files:")
    for path in payload.affected_files:
        body_lines.append(f"  - `{path}`")
    body_lines.append("- allowed resources:")
    for resource in payload.allowed_resources:
        body_lines.append(f"  - {resource}")
    body_lines.append("")

    body_lines.append("## 합의 vs 충돌")
    body_lines.append("")
    body_lines.append("- proposal_only: true")
    body_lines.append("- ready_for_dispatch: false")
    body_lines.append(
        f"- chairman_required: {_yaml_scalar(payload.chairman_required)}"
    )
    if payload.conflict_summary is None:
        body_lines.append("- 상태: 합의 (마아트/외부 AI critique 일치)")
    else:
        body_lines.append("- 상태: 충돌")
        body_lines.append(f"- conflict_summary: {payload.conflict_summary}")
    body_lines.append("")

    body_lines.append("## 다음 단계")
    body_lines.append("")
    for step in payload.next_steps:
        body_lines.append(f"- {step}")
    body_lines.append("")

    return "\n".join(frontmatter_lines + body_lines)


def filename_for(proposed_task_id: str, fixed_timestamp: str) -> str:
    """draft md 파일명을 결정적으로 산출한다.

    예: ``proposed_task_id='task-2486'``,
    ``fixed_timestamp='2026-05-08T00:00:00Z'``
    → ``draft-task-2486-2026-05-08T00-00-00Z.md``.

    Args:
        proposed_task_id: 제안된 다음 task_id.
        fixed_timestamp: ISO8601 (``Z`` 접미사) timestamp.

    Returns:
        파일시스템에 안전한 파일명 (``:`` → ``-`` 치환).
    """
    safe_ts = fixed_timestamp.replace(":", "-")
    return f"draft-{proposed_task_id}-{safe_ts}.md"


def write_draft(
    payload: DraftPayload,
    output_dir: Path,
) -> Path:
    """draft md를 출력 디렉토리에 기록하고 그 경로를 반환한다.

    Args:
        payload: 렌더링할 :class:`DraftPayload`.
        output_dir: 출력 디렉토리 (없으면 생성).

    Returns:
        실제로 기록된 파일의 절대 경로.
    """
    output_dir.mkdir(parents=True, exist_ok=True)
    target = output_dir / filename_for(
        payload.proposed_task_id, payload.generated_at
    )
    target.write_text(render_draft(payload), encoding="utf-8")
    return target.resolve()
