"""Mermaid diagram templates and generators."""
from __future__ import annotations

from typing import Sequence


# ─── Template library ─────────────────────────────────────────────────────────

TEMPLATES: dict[str, str] = {
    "flowchart": """\
flowchart TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Action A]
    B -->|No| D[Action B]
    C --> E[End]
    D --> E""",

    "flowchart-lr": """\
flowchart LR
    A[Input] --> B[Process]
    B --> C{Valid?}
    C -->|Yes| D[Output]
    C -->|No| E[Error]
    E --> A""",

    "sequence": """\
sequenceDiagram
    participant Client
    participant Server
    participant DB
    Client->>Server: Request
    Server->>DB: Query
    DB-->>Server: Result
    Server-->>Client: Response""",

    "class": """\
classDiagram
    class Animal {
        +String name
        +int age
        +makeSound()
    }
    class Dog {
        +String breed
        +fetch()
    }
    class Cat {
        +bool indoor
        +purr()
    }
    Animal <|-- Dog
    Animal <|-- Cat""",

    "er": """\
erDiagram
    USER {
        int id PK
        string name
        string email
        datetime created_at
    }
    POST {
        int id PK
        string title
        text content
        int user_id FK
    }
    COMMENT {
        int id PK
        text body
        int post_id FK
        int user_id FK
    }
    USER ||--o{ POST : writes
    POST ||--o{ COMMENT : has
    USER ||--o{ COMMENT : writes""",

    "gantt": """\
gantt
    title Project Timeline
    dateFormat YYYY-MM-DD
    section Planning
        Research           :a1, 2024-01-01, 7d
        Design             :a2, after a1, 5d
    section Development
        Backend            :b1, after a2, 14d
        Frontend           :b2, after a2, 14d
    section Launch
        Testing            :c1, after b1, 7d
        Deployment         :c2, after c1, 2d""",

    "state": """\
stateDiagram-v2
    [*] --> Idle
    Idle --> Running : start
    Running --> Paused : pause
    Paused --> Running : resume
    Running --> Done : complete
    Done --> [*]
    Running --> Error : fail
    Error --> Idle : reset""",

    "pie": """\
pie title Distribution
    "Category A" : 42
    "Category B" : 28
    "Category C" : 20
    "Category D" : 10""",

    "git": """\
gitGraph
    commit id: "init"
    branch feature
    checkout feature
    commit id: "add feature"
    commit id: "fix bug"
    checkout main
    merge feature
    commit id: "release v1.0""",

    "mindmap": """\
mindmap
  root((Project))
    Frontend
      React
      TypeScript
      CSS
    Backend
      Python
      FastAPI
      PostgreSQL
    DevOps
      Docker
      CI/CD
      Monitoring""",

    "timeline": """\
timeline
    title History of AI
    section 1950s-1970s
        1950 : Turing Test proposed
        1956 : Dartmouth Conference
    section 1980s-2000s
        1986 : Backpropagation
        1997 : Deep Blue beats Kasparov
    section 2010s-2020s
        2012 : AlexNet breakthrough
        2017 : Transformer architecture
        2022 : ChatGPT released""",

    "block": """\
block-beta
    columns 3
    A["Web Client"]:1 space B["Load Balancer"]:1
    space:3
    C["App Server 1"] D["App Server 2"] E["App Server 3"]
    space:3
    F["Database"]:3

    A --> B
    B --> C
    B --> D
    B --> E
    C --> F
    D --> F
    E --> F""",

    "xychart": """\
xychart-beta
    title "Monthly Revenue"
    x-axis [Jan, Feb, Mar, Apr, May, Jun]
    y-axis "Revenue ($K)" 0 --> 100
    bar [30, 45, 38, 62, 78, 55]
    line [30, 45, 38, 62, 78, 55]""",

    "c4-context": """\
C4Context
    title System Context
    Person(user, "User", "A person using the system")
    System(system, "Main System", "Core application")
    System_Ext(email, "Email System", "Sends notifications")
    Rel(user, system, "Uses", "HTTPS")
    Rel(system, email, "Sends emails via", "SMTP")""",

    "requirement": """\
requirementDiagram
    requirement test_req {
        id: 1
        text: The system shall handle 1000 concurrent users
        risk: high
        verifymethod: test
    }
    element test_entity {
        type: simulation
    }
    test_entity - satisfies -> test_req""",
}

TEMPLATE_DESCRIPTIONS: dict[str, str] = {
    "flowchart": "Vertical flowchart (top-down)",
    "flowchart-lr": "Horizontal flowchart (left-right)",
    "sequence": "Sequence / interaction diagram",
    "class": "Class diagram (OOP)",
    "er": "Entity-relationship diagram",
    "gantt": "Gantt / project timeline",
    "state": "State machine diagram",
    "pie": "Pie chart",
    "git": "Git branching flow",
    "mindmap": "Mind map / hierarchy",
    "timeline": "Historical timeline",
    "block": "Block architecture diagram",
    "xychart": "XY chart (bar + line)",
    "c4-context": "C4 context diagram",
    "requirement": "Requirement diagram",
}


# ─── Builders ─────────────────────────────────────────────────────────────────

def flowchart(
    nodes: list[tuple[str, str]],
    edges: list[tuple[str, str, str]],
    direction: str = "TD",
    title: str = "",
) -> str:
    """Build a flowchart from node/edge lists.

    nodes: [(id, label), ...]
    edges: [(from_id, to_id, label), ...]
    direction: TD | LR | BT | RL
    """
    lines = [f"flowchart {direction}"]
    if title:
        lines.insert(0, f"%% {title}")

    for nid, label in nodes:
        lines.append(f"    {nid}[{label}]")

    for src, dst, lbl in edges:
        if lbl:
            lines.append(f"    {src} -->|{lbl}| {dst}")
        else:
            lines.append(f"    {src} --> {dst}")

    return "\n".join(lines)


def sequence_diagram(
    participants: list[str],
    messages: list[tuple[str, str, str, bool]],
    title: str = "",
) -> str:
    """Build a sequence diagram.

    messages: [(from, to, label, is_return), ...]
    """
    lines = ["sequenceDiagram"]
    if title:
        lines.append(f"    title {title}")

    for p in participants:
        lines.append(f"    participant {p}")

    for src, dst, lbl, is_ret in messages:
        arrow = "-->>" if is_ret else "->>"
        lines.append(f"    {src}{arrow}{dst}: {lbl}")

    return "\n".join(lines)


def class_diagram(
    classes: list[dict],
    relations: list[tuple[str, str, str]],
) -> str:
    """Build a class diagram.

    classes: [{"name": str, "attrs": [str], "methods": [str]}, ...]
    relations: [(A, B, type)] where type is <|--, --|>, -->, <--, --
    """
    lines = ["classDiagram"]

    for cls in classes:
        lines.append(f"    class {cls['name']} {{")
        for attr in cls.get("attrs", []):
            lines.append(f"        {attr}")
        for method in cls.get("methods", []):
            lines.append(f"        {method}()")
        lines.append("    }")

    for a, b, rel in relations:
        lines.append(f"    {a} {rel} {b}")

    return "\n".join(lines)


def er_diagram(
    entities: list[dict],
    relationships: list[tuple[str, str, str, str, str]],
) -> str:
    """Build an ER diagram.

    entities: [{"name": str, "attrs": [(type, name, constraint), ...]}, ...]
    relationships: [(entity_a, cardinality_a, cardinality_b, entity_b, label), ...]
      cardinality: ||, |o, }|, }o, o|, o{, |{, }{ (standard crow's foot)
    """
    lines = ["erDiagram"]

    for ent in entities:
        lines.append(f"    {ent['name']} {{")
        for atype, aname, *rest in ent.get("attrs", []):
            constraint = rest[0] if rest else ""
            lines.append(f"        {atype} {aname} {constraint}".rstrip())
        lines.append("    }")

    for a, ca, cb, b, label in relationships:
        lines.append(f"    {a} {ca}--{cb} {b} : {label}")

    return "\n".join(lines)


def gantt_chart(
    title: str,
    sections: list[dict],
    date_format: str = "YYYY-MM-DD",
) -> str:
    """Build a Gantt chart.

    sections: [{"name": str, "tasks": [{"name": str, "id": str, "start": str, "duration": str}, ...]}, ...]
    """
    lines = ["gantt", f"    title {title}", f"    dateFormat {date_format}"]

    for sec in sections:
        lines.append(f"    section {sec['name']}")
        for task in sec.get("tasks", []):
            tid = task.get("id", "")
            start = task.get("start", "")
            dur = task.get("duration", "1d")
            if tid:
                lines.append(f"        {task['name']} :{tid}, {start}, {dur}")
            else:
                lines.append(f"        {task['name']} :{start}, {dur}")

    return "\n".join(lines)


def pie_chart(values: dict[str, float], title: str = "") -> str:
    """Build a Mermaid pie chart."""
    lines = ["pie"]
    if title:
        lines[0] = f"pie title {title}"
    for label, val in values.items():
        lines.append(f'    "{label}" : {val}')
    return "\n".join(lines)


def state_diagram(
    states: list[str],
    transitions: list[tuple[str, str, str]],
    initial: str = "",
    final: list[str] | None = None,
) -> str:
    """Build a state diagram.

    transitions: [(from, to, label), ...]
    """
    lines = ["stateDiagram-v2"]
    if initial:
        lines.append(f"    [*] --> {initial}")

    for src, dst, lbl in transitions:
        if lbl:
            lines.append(f"    {src} --> {dst} : {lbl}")
        else:
            lines.append(f"    {src} --> {dst}")

    for f in (final or []):
        lines.append(f"    {f} --> [*]")

    return "\n".join(lines)


def mindmap(root: str, branches: dict) -> str:
    """Build a mind map from a nested dict."""
    lines = ["mindmap", f"  root(({root}))"]

    def _render(node: dict | list | str, depth: int) -> None:
        indent = "  " * depth
        if isinstance(node, dict):
            for key, val in node.items():
                lines.append(f"{indent}{key}")
                _render(val, depth + 1)
        elif isinstance(node, list):
            for item in node:
                _render(item, depth)
        else:
            lines.append(f"{indent}{node}")

    _render(branches, 2)
    return "\n".join(lines)


# ─── Listing helpers ──────────────────────────────────────────────────────────

def list_templates() -> str:
    """Return a formatted list of available templates."""
    lines = ["Available Mermaid templates:", ""]
    for key, desc in TEMPLATE_DESCRIPTIONS.items():
        lines.append(f"  {key:<20} {desc}")
    return "\n".join(lines)


def get_template(name: str) -> str | None:
    """Return a template by name, or None."""
    return TEMPLATES.get(name)


def wrap_in_fence(diagram: str, lang: str = "mermaid") -> str:
    """Wrap diagram in a markdown fenced code block."""
    return f"```{lang}\n{diagram}\n```"
