"""HTML renderer for nim-audit output."""

from __future__ import annotations

from typing import Any

from jinja2 import Environment, BaseLoader

from nim_audit.renderers.base import BaseRenderer, OutputFormat, RenderContext


# Default HTML template
DEFAULT_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>
    <style>
        :root {
            --bg-color: #1a1a2e;
            --card-bg: #16213e;
            --text-color: #eee;
            --accent-color: #0f3460;
            --success-color: #00bf63;
            --warning-color: #ffc107;
            --error-color: #dc3545;
            --info-color: #17a2b8;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
            background-color: var(--bg-color);
            color: var(--text-color);
            line-height: 1.6;
            padding: 2rem;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        h1 {
            color: var(--text-color);
            margin-bottom: 1rem;
            border-bottom: 2px solid var(--accent-color);
            padding-bottom: 0.5rem;
        }

        h2 {
            color: var(--text-color);
            margin: 1.5rem 0 1rem;
        }

        .card {
            background-color: var(--card-bg);
            border-radius: 8px;
            padding: 1.5rem;
            margin-bottom: 1rem;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
        }

        .status-pass {
            color: var(--success-color);
            font-weight: bold;
        }

        .status-fail {
            color: var(--error-color);
            font-weight: bold;
        }

        .badge {
            display: inline-block;
            padding: 0.25rem 0.5rem;
            border-radius: 4px;
            font-size: 0.875rem;
            font-weight: 500;
        }

        .badge-error {
            background-color: var(--error-color);
        }

        .badge-warning {
            background-color: var(--warning-color);
            color: #000;
        }

        .badge-info {
            background-color: var(--info-color);
        }

        .badge-success {
            background-color: var(--success-color);
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin: 1rem 0;
        }

        th, td {
            padding: 0.75rem;
            text-align: left;
            border-bottom: 1px solid var(--accent-color);
        }

        th {
            background-color: var(--accent-color);
            font-weight: 600;
        }

        tr:hover {
            background-color: rgba(255, 255, 255, 0.05);
        }

        code {
            background-color: var(--accent-color);
            padding: 0.2rem 0.4rem;
            border-radius: 4px;
            font-family: 'Monaco', 'Menlo', monospace;
            font-size: 0.875rem;
        }

        .summary-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 1rem;
            margin: 1rem 0;
        }

        .summary-item {
            text-align: center;
            padding: 1rem;
            background-color: var(--accent-color);
            border-radius: 8px;
        }

        .summary-value {
            font-size: 2rem;
            font-weight: bold;
        }

        .summary-label {
            font-size: 0.875rem;
            opacity: 0.8;
        }

        .timestamp {
            font-size: 0.875rem;
            opacity: 0.7;
        }

        .breaking-change {
            border-left: 4px solid var(--error-color);
            padding-left: 1rem;
            margin: 1rem 0;
        }

        footer {
            margin-top: 2rem;
            text-align: center;
            opacity: 0.6;
            font-size: 0.875rem;
        }
    </style>
</head>
<body>
    <div class="container">
        {{ content }}

        <footer>
            Generated by nim-audit
        </footer>
    </div>
</body>
</html>
"""


class HTMLRenderer(BaseRenderer):
    """Renderer for HTML output format.

    Converts audit results to styled HTML reports.

    Example:
        renderer = HTMLRenderer()
        html_str = renderer.render(diff_report, context)
    """

    def __init__(self, template: str | None = None) -> None:
        """Initialize the HTML renderer.

        Args:
            template: Custom Jinja2 template string
        """
        self._template = template or DEFAULT_TEMPLATE
        self._env = Environment(loader=BaseLoader(), autoescape=True)

    @property
    def format(self) -> OutputFormat:
        """The output format this renderer produces."""
        return OutputFormat.HTML

    def render(self, data: Any, context: RenderContext) -> str:
        """Render data to an HTML string.

        Args:
            data: The data to render
            context: Rendering context

        Returns:
            HTML string
        """
        # Generate content based on data type
        if hasattr(data, "__class__"):
            class_name = data.__class__.__name__

            if class_name == "DiffReport":
                title = "NIM Diff Report"
                content = self._render_diff_report(data)
            elif class_name == "ConfigReport":
                title = "NIM Configuration Report"
                content = self._render_config_report(data)
            elif class_name == "CompatReport":
                title = "GPU Compatibility Report"
                content = self._render_compat_report(data)
            elif class_name == "LintResult":
                title = "Lint Report"
                content = self._render_lint_result(data)
            else:
                title = "Report"
                content = self._render_generic(data)
        else:
            title = "Report"
            content = self._render_generic(data)

        # Load custom template if provided
        template_str = self._template
        if context.template:
            try:
                from pathlib import Path

                template_str = Path(context.template).read_text()
            except Exception:
                pass

        template = self._env.from_string(template_str)
        return template.render(title=title, content=content)

    def _render_diff_report(self, report: Any) -> str:
        """Render diff report content."""
        breaking_html = ""
        if report.breaking_changes:
            breaking_items = "".join(
                f"""
                <div class="breaking-change">
                    <h3>{bc.title}</h3>
                    <p>{bc.description}</p>
                    <p><strong>Impact:</strong> {bc.impact}</p>
                    {f'<p><strong>Migration:</strong> {bc.migration}</p>' if bc.migration else ''}
                </div>
                """
                for bc in report.breaking_changes
            )
            breaking_html = f"<h2>Breaking Changes</h2>{breaking_items}"

        rows = "".join(
            f"""
            <tr>
                <td>{entry.category.value}</td>
                <td><span class="badge badge-{self._change_type_class(entry.change_type.value)}">{entry.change_type.value}</span></td>
                <td><code>{entry.path}</code></td>
                <td>{entry.old_value or '-'}</td>
                <td>{entry.new_value or '-'}</td>
            </tr>
            """
            for entry in report.entries
        )

        return f"""
        <h1>NIM Diff Report</h1>
        <p class="timestamp">Generated: {report.generated_at.isoformat()}</p>

        <div class="card">
            <h2>Images Compared</h2>
            <p><strong>Source:</strong> <code>{report.source_image.reference}</code></p>
            <p><strong>Target:</strong> <code>{report.target_image.reference}</code></p>
        </div>

        <div class="card">
            <h2>Summary</h2>
            <div class="summary-grid">
                <div class="summary-item">
                    <div class="summary-value">{report.total_changes}</div>
                    <div class="summary-label">Total Changes</div>
                </div>
                <div class="summary-item">
                    <div class="summary-value" style="color: var(--success-color)">{report.added_count}</div>
                    <div class="summary-label">Added</div>
                </div>
                <div class="summary-item">
                    <div class="summary-value" style="color: var(--error-color)">{report.removed_count}</div>
                    <div class="summary-label">Removed</div>
                </div>
                <div class="summary-item">
                    <div class="summary-value" style="color: var(--warning-color)">{report.modified_count}</div>
                    <div class="summary-label">Modified</div>
                </div>
                <div class="summary-item">
                    <div class="summary-value" style="color: var(--error-color)">{len(report.breaking_changes)}</div>
                    <div class="summary-label">Breaking</div>
                </div>
            </div>
        </div>

        {breaking_html}

        <div class="card">
            <h2>All Changes</h2>
            <table>
                <thead>
                    <tr>
                        <th>Category</th>
                        <th>Type</th>
                        <th>Path</th>
                        <th>Old Value</th>
                        <th>New Value</th>
                    </tr>
                </thead>
                <tbody>
                    {rows}
                </tbody>
            </table>
        </div>
        """

    def _render_config_report(self, report: Any) -> str:
        """Render config report content."""
        warnings_html = ""
        if report.warnings:
            items = "".join(f"<li>{w}</li>" for w in report.warnings)
            warnings_html = f'<div class="card"><h2>Warnings</h2><ul>{items}</ul></div>'

        rows = "".join(
            f"""
            <tr>
                <td><code>{entry.name}</code></td>
                <td>{entry.value or '-'}</td>
                <td>{entry.default_value or '-'}</td>
                <td><span class="badge badge-{self._impact_class(entry.impact.level.value if entry.impact else 'none')}">{entry.impact.level.value if entry.impact else '-'}</span></td>
                <td>{entry.description or '-'}</td>
            </tr>
            """
            for entry in report.entries
            if entry.is_set
        )

        return f"""
        <h1>NIM Configuration Report</h1>

        <div class="card">
            <p><strong>Image:</strong> <code>{report.image_reference}</code></p>
        </div>

        {warnings_html}

        <div class="card">
            <h2>Configuration</h2>
            <table>
                <thead>
                    <tr>
                        <th>Variable</th>
                        <th>Value</th>
                        <th>Default</th>
                        <th>Impact</th>
                        <th>Description</th>
                    </tr>
                </thead>
                <tbody>
                    {rows}
                </tbody>
            </table>
        </div>
        """

    def _render_compat_report(self, report: Any) -> str:
        """Render compatibility report content."""
        status_class = "status-pass" if report.compatible else "status-fail"
        status_text = "Compatible" if report.compatible else "Not Compatible"

        return f"""
        <h1>GPU Compatibility Report</h1>

        <div class="card">
            <p><strong>Image:</strong> <code>{report.image_reference}</code></p>
            <p><strong>Status:</strong> <span class="{status_class}">{status_text}</span></p>
        </div>

        <div class="card">
            <h2>Configuration</h2>
            <p><strong>GPU:</strong> {report.gpu.name if report.gpu else 'Not specified'}</p>
            <p><strong>Driver Version:</strong> {report.driver_version or 'Not specified'}</p>
        </div>

        <div class="card">
            <h2>Compatibility Checks</h2>
            <table>
                <tr>
                    <td>Compute Capability</td>
                    <td><span class="badge badge-{'success' if report.compute_compatible else 'error'}">{'Pass' if report.compute_compatible else 'Fail'}</span></td>
                </tr>
                <tr>
                    <td>GPU Memory</td>
                    <td><span class="badge badge-{'success' if report.memory_compatible else 'error'}">{'Pass' if report.memory_compatible else 'Fail'}</span></td>
                </tr>
                <tr>
                    <td>Driver Version</td>
                    <td><span class="badge badge-{'success' if report.driver_compatible else 'error'}">{'Pass' if report.driver_compatible else 'Fail'}</span></td>
                </tr>
            </table>
        </div>
        """

    def _render_lint_result(self, result: Any) -> str:
        """Render lint result content."""
        status_class = "status-pass" if result.passed else "status-fail"
        status_text = "Passed" if result.passed else "Failed"

        rows = "".join(
            f"""
            <tr>
                <td><span class="badge badge-{v.severity.value}">{v.severity.value}</span></td>
                <td>{v.rule.name}</td>
                <td>{v.message}</td>
                <td>{v.rule.remediation or '-'}</td>
            </tr>
            """
            for v in result.violations
        )

        return f"""
        <h1>Lint Report</h1>

        <div class="card">
            <p><strong>Image:</strong> <code>{result.image_reference}</code></p>
            <p><strong>Policy:</strong> {result.policy.name} v{result.policy.version}</p>
            <p><strong>Status:</strong> <span class="{status_class}">{status_text}</span></p>
        </div>

        <div class="card">
            <h2>Summary</h2>
            <div class="summary-grid">
                <div class="summary-item">
                    <div class="summary-value">{len(result.policy.enabled_rules)}</div>
                    <div class="summary-label">Total Rules</div>
                </div>
                <div class="summary-item">
                    <div class="summary-value" style="color: var(--error-color)">{result.error_count}</div>
                    <div class="summary-label">Errors</div>
                </div>
                <div class="summary-item">
                    <div class="summary-value" style="color: var(--warning-color)">{result.warning_count}</div>
                    <div class="summary-label">Warnings</div>
                </div>
            </div>
        </div>

        {'<div class="card"><h2>Violations</h2><table><thead><tr><th>Severity</th><th>Rule</th><th>Message</th><th>Remediation</th></tr></thead><tbody>' + rows + '</tbody></table></div>' if result.violations else '<div class="card"><p>No violations found!</p></div>'}
        """

    def _render_generic(self, data: Any) -> str:
        """Render generic data."""
        import json

        from pydantic import BaseModel

        if isinstance(data, BaseModel):
            dict_data = data.model_dump(mode="json")
        elif isinstance(data, dict):
            dict_data = data
        else:
            dict_data = {"data": str(data)}

        json_str = json.dumps(dict_data, indent=2, default=str)

        return f"""
        <h1>Report</h1>
        <div class="card">
            <pre><code>{json_str}</code></pre>
        </div>
        """

    @staticmethod
    def _change_type_class(change_type: str) -> str:
        """Get badge class for change type."""
        return {"added": "success", "removed": "error", "modified": "warning"}.get(
            change_type, "info"
        )

    @staticmethod
    def _impact_class(impact: str) -> str:
        """Get badge class for impact level."""
        return {
            "critical": "error",
            "high": "error",
            "medium": "warning",
            "low": "info",
        }.get(impact, "info")
