"""Visualize the validation chain hierarchy with properties."""

from dataclasses import dataclass
from pathlib import Path

from pydantic import BaseModel


@dataclass
class ClassInfo:
    """Information about a validation class."""

    name: str
    module: str
    own_fields: list[str]
    inherited_fields: list[str]
    parent_name: str | None


def get_own_fields(cls: type[BaseModel]) -> list[str]:
    """Get fields defined directly on this class, not inherited."""
    own_fields: list[str] = []
    parent_fields: set[str] = set()

    for parent in cls.__mro__[1:]:
        if hasattr(parent, "model_fields"):
            parent_fields.update(parent.model_fields.keys())

    for field_name in cls.model_fields:
        if field_name not in parent_fields:
            own_fields.append(field_name)

    return sorted(own_fields)


def get_inherited_fields(cls: type[BaseModel]) -> list[str]:
    """Get all inherited fields from parent classes."""
    inherited: set[str] = set()

    for parent in cls.__mro__[1:]:
        if hasattr(parent, "model_fields"):
            inherited.update(parent.model_fields.keys())

    return sorted(inherited)


def get_parent_class(cls: type[BaseModel]) -> type[BaseModel] | None:
    """Get the immediate parent class that is a BaseModel."""
    for parent in cls.__mro__[1:]:
        if parent is BaseModel:
            return None
        if issubclass(parent, BaseModel) and parent is not BaseModel:
            return parent
    return None


def analyze_validation_chain() -> list[ClassInfo]:
    """Analyze the validation chain and return class info for each class."""
    from . import (
        Base,
        ConfigToCrawl,
        CrawlerToData,
        CrawlToProxy,
        DataToDatabase,
        InputToConfig,
        InputToCrawl,
        InputToCrawler,
        InputToData,
        InputToProxy,
        ProxyToCrawler,
    )

    classes = [
        Base,
        InputToConfig,
        ConfigToCrawl,
        InputToCrawl,
        CrawlToProxy,
        InputToProxy,
        ProxyToCrawler,
        InputToCrawler,
        CrawlerToData,
        InputToData,
        DataToDatabase,
    ]

    chain: list[ClassInfo] = []

    for cls in classes:
        parent = get_parent_class(cls)
        chain.append(
            ClassInfo(
                name=cls.__name__,
                module=cls.__module__.split(".")[-1],
                own_fields=get_own_fields(cls),
                inherited_fields=get_inherited_fields(cls),
                parent_name=parent.__name__ if parent else None,
            )
        )

    return chain


def generate_mermaid_diagram(chain: list[ClassInfo]) -> str:
    """Generate a Mermaid flowchart diagram of the validation chain."""
    lines = [
        "flowchart TD",
        "",
    ]

    for info in chain:
        fields_str = "<br/>".join(info.own_fields) if info.own_fields else "(no new fields)"
        node_label = f'"{info.name}<br/>---<br/>{fields_str}"'
        lines.append(f"    {info.name}[{node_label}]")

    lines.append("")

    for info in chain:
        if info.parent_name:
            lines.append(f"    {info.parent_name} --> {info.name}")

    lines.append("")

    module_classes: dict[str, list[str]] = {}
    for info in chain:
        module_classes.setdefault(info.module, []).append(info.name)

    for module, class_names in module_classes.items():
        lines.append(f'    subgraph "{module}.py"')
        for class_name in class_names:
            lines.append(f"        {class_name}")
        lines.append("    end")

    return "\n".join(lines)


def generate_html(mermaid_code: str) -> str:
    """Generate HTML file with embedded Mermaid diagram."""
    return f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Validation Chain Visualization</title>
    <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: #f5f5f5;
        }}
        h1 {{
            color: #333;
            text-align: center;
        }}
        .mermaid {{
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }}
        .legend {{
            margin-top: 20px;
            padding: 15px;
            background: white;
            border-radius: 8px;
        }}
        .legend h3 {{
            margin-top: 0;
        }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin-top: 10px;
        }}
        th, td {{
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }}
        th {{
            background: #f0f0f0;
        }}
    </style>
</head>
<body>
    <h1>Validation Chain Hierarchy</h1>
    <div class="mermaid">
{mermaid_code}
    </div>
    <script>
        mermaid.initialize({{ startOnLoad: true, theme: "default" }});
    </script>
</body>
</html>"""


def print_text_visualization(chain: list[ClassInfo]) -> None:
    """Print a text-based visualization of the validation chain."""
    print("=" * 80)
    print("VALIDATION CHAIN HIERARCHY")
    print("=" * 80)
    print()

    for i, info in enumerate(chain):
        indent = "  " * i
        print(f"{indent}{info.name} ({info.module}.py)")
        if info.own_fields:
            print(f"{indent}  New fields:")
            for field in info.own_fields:
                print(f"{indent}    - {field}")
        else:
            print(f"{indent}  (no new fields)")
        print()

    print("=" * 80)
    print("INHERITANCE CHAIN")
    print("=" * 80)
    print(" -> ".join(info.name for info in chain))
    print()

    print("=" * 80)
    print("CUMULATIVE FIELDS BY CLASS")
    print("=" * 80)
    for info in chain:
        total_fields = len(info.own_fields) + len(info.inherited_fields)
        print(f"\n{info.name}: {total_fields} total fields")
        print(f"  Own ({len(info.own_fields)}): {', '.join(info.own_fields) or 'none'}")
        print(f"  Inherited ({len(info.inherited_fields)}): {len(info.inherited_fields)} fields")


def save_html_visualization(output_path: Path | None = None) -> Path:
    """Generate and save HTML visualization to file."""
    chain = analyze_validation_chain()
    mermaid_code = generate_mermaid_diagram(chain)
    html_content = generate_html(mermaid_code)

    if output_path is None:
        output_path = Path(__file__).parent.parent.parent / "documentation" / "validation_chain.html"

    output_path.parent.mkdir(parents=True, exist_ok=True)
    output_path.write_text(html_content, encoding="utf-8")

    return output_path


def main() -> None:
    """Run the visualization."""
    chain = analyze_validation_chain()

    print_text_visualization(chain)

    output_path = save_html_visualization()
    print(f"\nHTML visualization saved to: {output_path}")


if __name__ == "__main__":
    main()
