"""Draft formatter — assembles outline + sections into I-D text format."""

from __future__ import annotations

import re
import textwrap
from datetime import datetime, timezone, timedelta


def _strip_markdown(text: str) -> str:
    """Remove markdown formatting that Claude may leak into output."""
    # Bold/italic
    text = re.sub(r'\*\*\*(.+?)\*\*\*', r'\1', text)
    text = re.sub(r'\*\*(.+?)\*\*', r'\1', text)
    text = re.sub(r'\*(.+?)\*', r'\1', text)
    text = re.sub(r'___(.+?)___', r'\1', text)
    text = re.sub(r'__(.+?)__', r'\1', text)
    text = re.sub(r'_(.+?)_', r'\1', text)
    # Markdown headers → plain text
    text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE)
    # Code fences
    text = re.sub(r'```\w*\n?', '', text)
    # Inline code
    text = re.sub(r'`([^`]+)`', r'\1', text)
    # Markdown links [text](url) → text
    text = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', text)
    return text


class DraftFormatter:
    @staticmethod
    def format_draft(outline: dict, sections: list[str], family_name: str = "") -> str:
        """Assemble outline + sections into I-D text format."""
        title = outline["title"]
        draft_name = DraftFormatter._make_draft_name(title, family_name)

        parts = []
        parts.append(DraftFormatter._header_block(outline, draft_name))
        parts.append("")
        parts.append("Abstract")
        parts.append("")
        parts.append(DraftFormatter._wrap_text(_strip_markdown(outline.get("abstract", ""))))
        parts.append("")
        parts.append(DraftFormatter._status_memo(outline))
        parts.append("")

        # Terminology section (if outline has terminology)
        terms = outline.get("terminology", {})
        if terms:
            parts.append(DraftFormatter._terminology_section(outline))
            parts.append("")

        # Table of Contents
        parts.append("Table of Contents")
        parts.append("")
        section_list = outline.get("sections", [])
        for i, section in enumerate(section_list, 1):
            stitle = section.get("title", f"Section {i}")
            dots = "." * max(1, 60 - len(stitle))
            parts.append(f"   {i}.  {stitle}  {dots}  {i + 2}")
        ref_num = len(section_list) + 1
        parts.append(f"   {ref_num}.  References  {'.' * (60 - len('References'))}  {ref_num + 2}")
        parts.append("")

        # Sections
        for i, (section_info, section_text) in enumerate(
            zip(section_list, sections), 1
        ):
            stitle = section_info.get("title", f"Section {i}")
            parts.append(f"{i}.  {stitle}")
            parts.append("")
            parts.append(DraftFormatter._wrap_text(_strip_markdown(section_text)))
            parts.append("")

        # References section
        parts.append(DraftFormatter._references_section(outline))
        parts.append("")

        # Author's Address
        parts.append("Author's Address")
        parts.append("")
        parts.append("   Generated by IETF Draft Analyzer")
        if family_name:
            parts.append(f"   Family: {family_name}")
        parts.append(f"   {datetime.now(timezone.utc).strftime('%Y-%m-%d')}")
        parts.append("")

        return "\n".join(parts)

    @staticmethod
    def _make_draft_name(title: str, family_name: str = "") -> str:
        """Generate a draft name from title."""
        words = title.lower().split()
        slug = "-".join(w for w in words[:4] if w.isalnum())
        if family_name:
            return f"draft-{family_name}-{slug}-00"
        return f"draft-ai-{slug}-00"

    @staticmethod
    def _header_block(outline: dict, draft_name: str) -> str:
        """Proper I-D header."""
        now = datetime.now(timezone.utc)
        expires = now + timedelta(days=185)
        date_str = now.strftime("%B %Y")
        exp_str = expires.strftime("%B %d, %Y")
        status = outline.get("intended_status", "Informational")
        wg = outline.get("target_wg", "individual")
        title = outline["title"]

        lines = []
        # Right-align WG/date to col 72
        id_label = "Internet-Draft"
        pad = max(1, 72 - len(id_label) - len(wg))
        lines.append(f"{id_label}{' ' * pad}{wg}")
        is_label = f"Intended status: {status}"
        pad2 = max(1, 72 - len(is_label) - len(date_str))
        lines.append(f"{is_label}{' ' * pad2}{date_str}")
        lines.append(f"Expires: {exp_str}")
        lines.append("")
        lines.append("")
        lines.append(f"         {title}")
        lines.append(f"         {draft_name}")
        return "\n".join(lines)

    @staticmethod
    def _status_memo(outline: dict) -> str:
        """Status of This Memo boilerplate."""
        status = outline.get("intended_status", "Informational")
        lines = []
        lines.append("Status of This Memo")
        lines.append("")
        lines.append(DraftFormatter._wrap_text(
            "This Internet-Draft is submitted in full conformance with the "
            "provisions of BCP 78 and BCP 79."
        ))
        lines.append("")
        lines.append(DraftFormatter._wrap_text(
            f"This document is intended to have {status} status. "
            "Distribution of this memo is unlimited."
        ))
        return "\n".join(lines)

    @staticmethod
    def _references_section(outline: dict) -> str:
        """Normative + Informative References from outline data."""
        lines = []
        norm_refs = outline.get("normative_refs", [])
        info_refs = outline.get("informative_refs", [])

        ref_num = len(outline.get("sections", [])) + 1
        lines.append(f"{ref_num}.  References")
        lines.append("")

        if norm_refs:
            lines.append(f"{ref_num}.1.  Normative References")
            lines.append("")
            for ref in norm_refs:
                lines.append(f"   [{ref}]")
                lines.append(f"         {ref}")
                lines.append("")

        if info_refs:
            sub = "2" if norm_refs else "1"
            lines.append(f"{ref_num}.{sub}.  Informative References")
            lines.append("")
            for ref in info_refs:
                lines.append(f"   [{ref}]")
                lines.append(f"         {ref}")
                lines.append("")

        if not norm_refs and not info_refs:
            lines.append("   (No references specified)")
            lines.append("")

        return "\n".join(lines)

    @staticmethod
    def _terminology_section(outline: dict) -> str:
        """Terminology section from outline terminology dict."""
        terms = outline.get("terminology", {})
        if not terms:
            return ""

        lines = []
        lines.append("Terminology")
        lines.append("")
        lines.append(DraftFormatter._wrap_text(
            'The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL '
            'NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", '
            '"MAY", and "OPTIONAL" in this document are to be interpreted as '
            'described in BCP 14 [RFC2119] [RFC8174] when, and only when, they '
            'appear in all capitals, as shown here.'
        ))
        lines.append("")

        for term, definition in terms.items():
            lines.append(f"   {term}")
            lines.append(DraftFormatter._wrap_text(definition, indent=6))
            lines.append("")

        return "\n".join(lines)

    @staticmethod
    def _wrap_text(text: str, indent: int = 3, width: int = 69) -> str:
        """72-char line wrapping for I-D format."""
        prefix = " " * indent
        paragraphs = text.strip().split("\n\n")
        wrapped = []
        for para in paragraphs:
            # Preserve list items
            if para.strip().startswith("-") or para.strip().startswith("*"):
                inner_lines = para.strip().split("\n")
                for line in inner_lines:
                    line = line.strip()
                    sub_lines = textwrap.wrap(
                        line, width=width,
                        initial_indent=prefix,
                        subsequent_indent=prefix + "  ",
                    )
                    wrapped.append("\n".join(sub_lines))
            else:
                para = " ".join(para.split())  # Normalize whitespace
                lines = textwrap.wrap(
                    para, width=width,
                    initial_indent=prefix,
                    subsequent_indent=prefix,
                )
                wrapped.append("\n".join(lines))
        return "\n\n".join(wrapped)
