"""
Wikin:
    name: Generator

Generates HTML documentation from parsed module data.
"""

import os
import markdown
import jinja2
try:
    import tomllib
except ImportError:
    # Fallback for Python < 3.11 if tomli is installed
    try:
        import tomli as tomllib
    except ImportError:
        tomllib = None
from typing import List
from .parser import ModuleDoc

HTML_TEMPLATE = r"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ project_name }} v{{ version }}{% if current_module %} - {{ current_module.name }}{% endif %} - Documentation</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
    <style>
        :root {
            --primary: #6366f1;
            --primary-hover: #4f46e5;
            --bg: #0f172a;
            --sidebar-bg: #1e293b;
            --card-bg: rgba(30, 41, 59, 0.7);
            --text: #f8fafc;
            --text-muted: #94a3b8;
            --border: rgba(255, 255, 255, 0.1);
            --accent: #10b981;
        }

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

        body {
            font-family: 'Inter', sans-serif;
            background-color: var(--bg);
            color: var(--text);
            line-height: 1.6;
            display: flex;
            min-height: 100vh;
        }

        /* Sidebar */
        aside {
            width: 300px;
            background-color: var(--sidebar-bg);
            border-right: 1px solid var(--border);
            padding: 2rem;
            position: sticky;
            top: 0;
            height: 100vh;
            overflow-y: auto;
            z-index: 50;
        }

        .brand {
            font-size: 1.5rem;
            font-weight: 700;
            margin-bottom: 2rem;
            color: var(--primary);
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }
        
        .brand a {
            text-decoration: none;
            color: inherit;
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }

        .version {
            font-size: 0.8rem;
            background: var(--primary);
            color: white;
            padding: 0.2rem 0.6rem;
            border-radius: 9999px;
            font-weight: normal;
        }

        nav ul {
            list-style: none;
        }

        nav li {
            margin-bottom: 0.5rem;
        }

        nav a {
            color: var(--text-muted);
            text-decoration: none;
            transition: all 0.2s;
            font-size: 0.95rem;
            display: block;
            padding: 0.4rem 0.8rem;
            border-radius: 6px;
        }

        nav a:hover {
            color: var(--text);
            background: rgba(255, 255, 255, 0.05);
        }

        nav .active {
            color: var(--primary);
            background: rgba(99, 102, 241, 0.1);
            font-weight: 500;
        }

        /* Main Content */
        main {
            flex: 1;
            padding: 3rem 5rem;
            max-width: 1000px;
            margin: 0 auto;
        }

        h1, h2, h3 {
            margin-bottom: 1.5rem;
            font-weight: 700;
        }

        h1 { font-size: 2.5rem; margin-top: 0; }
        h2 { font-size: 1.8rem; margin-top: 3rem; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; color: var(--primary); }
        h3 { font-size: 1.3rem; margin-top: 2rem; }

        .doc-section {
            margin-bottom: 4rem;
        }

        .item {
            background: var(--card-bg);
            backdrop-filter: blur(8px);
            border: 1px solid var(--border);
            border-radius: 12px;
            padding: 1.5rem;
            margin-bottom: 1.5rem;
            transition: transform 0.2s, box-shadow 0.2s;
        }

        .item:hover {
            transform: translateY(-2px);
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
            border-color: rgba(99, 102, 241, 0.3);
        }

        .item-header {
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            margin-bottom: 1rem;
        }

        .item-name {
            font-family: 'Fira Code', monospace;
            font-weight: 600;
            font-size: 1.1rem;
            color: var(--accent);
        }

        .item-type {
            font-size: 0.7rem;
            text-transform: uppercase;
            letter-spacing: 0.05em;
            color: var(--text-muted);
            background: rgba(255, 255, 255, 0.05);
            padding: 0.2rem 0.5rem;
            border-radius: 4px;
        }

        .item-doc {
            font-size: 0.95rem;
            color: var(--text-muted);
        }

        code {
            font-family: 'Fira Code', monospace;
            background: rgba(0, 0, 0, 0.3);
            padding: 0.2rem 0.4rem;
            border-radius: 4px;
            font-size: 0.9em;
        }

        pre {
            background: #000;
            padding: 1rem;
            border-radius: 8px;
            overflow-x: auto;
            margin: 1rem 0;
        }

        pre code {
            background: transparent;
            padding: 0;
        }

        .signature {
            color: var(--primary);
            margin-bottom: 0.5rem;
            display: block;
            font-weight: 500;
        }

        .variable-value {
            font-family: 'Fira Code', monospace;
            color: #fb923c;
            margin-left: 0.5rem;
        }

        .category-header {
            margin-top: 3rem;
            margin-bottom: 1rem;
        }

        .highlight {
            background: rgba(99, 102, 241, 0.4);
            color: #fff;
            border-radius: 2px;
            padding: 0 1px;
        }

        .search-container {
            margin-bottom: 2rem;
            position: relative;
        }

        .search-input {
            width: 100%;
            background: rgba(255, 255, 255, 0.05);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 0.6rem 1rem 0.6rem 2.5rem;
            color: var(--text);
            font-family: inherit;
            font-size: 0.9rem;
            outline: none;
            transition: border-color 0.2s;
        }

        .search-input:focus {
            border-color: var(--primary);
        }

        .search-icon {
            position: absolute;
            left: 0.8rem;
            top: 50%;
            transform: translateY(-50%);
            color: var(--text-muted);
            pointer-events: none;
            z-index: 10;
        }

        .search-results {
            position: absolute;
            top: 100%;
            left: 0;
            right: 0;
            background: var(--sidebar-bg);
            border: 1px solid var(--border);
            border-radius: 8px;
            margin-top: 0.5rem;
            max-height: 400px;
            overflow-y: auto;
            display: none;
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
            z-index: 100;
        }

        .search-result-item {
            padding: 0.8rem 1rem;
            border-bottom: 1px solid var(--border);
            cursor: pointer;
            transition: background 0.2s;
            text-decoration: none;
            display: block;
            color: inherit;
        }

        .search-result-item:hover {
            background: rgba(255, 255, 255, 0.05);
        }

        .search-result-item:last-child {
            border-bottom: none;
        }

        .search-result-name {
            font-family: 'Fira Code', monospace;
            font-size: 0.9rem;
            color: var(--accent);
            display: block;
        }

        .search-result-type {
            font-size: 0.7rem;
            color: var(--text-muted);
            text-transform: uppercase;
            margin-bottom: 0.2rem;
            display: block;
        }

        .search-result-module {
            font-size: 0.75rem;
            color: var(--primary);
            margin-bottom: 0.4rem;
            display: block;
        }

        /* Responsive */
        @media (max-width: 768px) {
            body { flex-direction: column; }
            aside { width: 100%; height: auto; position: static; }
            main { padding: 2rem; }
        }

        .project-links {
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;
            margin-bottom: 2rem;
        }

        .project-link {
            flex: 1;
            min-width: fit-content;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.9rem;
            background: rgba(255, 255, 255, 0.05);
            color: var(--text-muted);
            padding: 0.6rem 1rem;
            border-radius: 8px;
            text-decoration: none;
            transition: all 0.2s;
            border: 1px solid var(--border);
            white-space: nowrap;
            line-height: normal;
        }

        .project-link:hover {
            background: var(--primary);
            color: white;
            border-color: var(--primary);
            transform: translateY(-1px);
        }
    </style>
</head>
<body>
    <aside>
        <div class="brand">
            <a href="{{ base_url }}index.html">{{ project_name }} <span class="version">v{{ version }}</span></a>
        </div>
        
        {% if links %}
        <div class="project-links">
            {% for name, url in links.items() %}
            <a href="{{ url }}" target="_blank" class="project-link">
                {{ name }}
            </a>
            {% endfor %}
        </div>
        {% endif %}
        
        <div class="search-container">
            <svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
            <input type="text" id="wikin-search" class="search-input" placeholder="Search across all modules..." autocomplete="off">
            <div id="search-results" class="search-results"></div>
        </div>

        <nav>
            <ul id="sidebar-list">
                {% for mod in modules | sort(attribute='name') %}
                <li data-name="{{ mod.name }}">
                    <a href="{{ module_prefix }}{{ mod.original_name }}.html" 
                       class="{% if current_module and current_module.original_name == mod.original_name %}active{% endif %}">
                        {{ mod.name }}
                    </a>
                </li>
                {% endfor %}
            </ul>
        </nav>
    </aside>
    <main>
        <div id="no-results" style="display: none; text-align: center; margin-top: 5rem; color: var(--text-muted);">
            <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" style="margin-bottom: 1rem; opacity: 0.5;">
                <circle cx="11" cy="11" r="8"></circle>
                <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
            </svg>
            <p>No results found for your search.</p>
        </div>

        <h1>{{ project_name }}</h1>
        <p style="color: var(--text-muted); margin-bottom: 3rem;">Documentation generated by Wikin.</p>
        
        <div id="content-wrapper">
            {% for mod in content_modules | sort(attribute='name') %}
            <section id="{{ mod.original_name | replace('.', '-') }}" class="doc-section" data-name="{{ mod.name }}">
                <h2>Module: {{ mod.name }}</h2>
                
                {% if mod.docstring %}
                <div class="module-doc searchable">{{ mod.docstring | markdown | safe }}</div>
                {% endif %}
                
                {% if mod.classes %}
                <div class="category-header"><h3>Classes</h3></div>
                {% for cls in mod.classes %}
                <div id="{{ mod.original_name | replace('.', '-') }}-{{ cls.name }}" class="item" data-name="{{ cls.name }}">
                    <div class="item-header">
                        <div>
                            <span class="item-name searchable">{{ cls.name }}</span>
                            <span class="item-type">class</span>
                        </div>
                    </div>
                    {% if cls.docstring %}
                    <div class="item-doc searchable">{{ cls.docstring | markdown | safe }}</div>
                    {% endif %}
                    
                    {% for method in cls.methods %}
                    <div id="{{ mod.original_name | replace('.', '-') }}-{{ cls.name }}-{{ method.name }}" class="sub-item" data-name="{{ method.name }}" style="margin-left: 1.5rem; margin-top: 1rem; border-left: 2px solid var(--border); padding-left: 1rem;">
                        <div class="item-header">
                            <span class="item-name searchable" style="font-size: 0.9rem;">{{ method.name }}</span>
                            <span class="item-type" style="font-size: 0.6rem;">method</span>
                        </div>
                        <code class="signature searchable" style="font-size: 0.8rem;">{{ method.signature }}</code>
                        {% if method.docstring %}
                        <div class="item-doc searchable" style="font-size: 0.85rem;">{{ method.docstring | markdown | safe }}</div>
                        {% endif %}
                    </div>
                    {% endfor %}
                </div>
                {% endfor %}
                {% endif %}

                {% if mod.functions %}
                <div class="category-header"><h3>Functions</h3></div>
                {% for func in mod.functions %}
                <div id="{{ mod.original_name | replace('.', '-') }}-{{ func.name }}" class="item" data-name="{{ func.name }}">
                    <div class="item-header">
                        <div>
                            <span class="item-name searchable">{{ func.name }}</span>
                            <span class="item-type">function</span>
                        </div>
                    </div>
                    <code class="signature searchable">{{ func.signature }}</code>
                    {% if func.docstring %}
                    <div class="item-doc searchable">{{ func.docstring | markdown | safe }}</div>
                    {% endif %}
                </div>
                {% endfor %}
                {% endif %}

                {% if mod.variables %}
                <div class="category-header"><h3>Variables</h3></div>
                {% for var in mod.variables %}
                <div id="{{ mod.original_name | replace('.', '-') }}-{{ var.name }}" class="item" data-name="{{ var.name }}">
                    <div class="item-header">
                        <div>
                            <span class="item-name searchable">{{ var.name }}</span>
                            <span class="item-type">variable</span>
                        </div>
                        <span class="variable-value">= {{ var.value }}</span>
                    </div>
                    {% if var.docstring %}
                    <div class="item-doc searchable">{{ var.docstring | markdown | safe }}</div>
                    {% endif %}
                </div>
                {% endfor %}
                {% endif %}
                
            </section>
            {% endfor %}
            
            {% if not current_module and multipage %}
            <div class="welcome-section" style="text-align: center; padding: 4rem 0;">
                <h2 style="border: none;">Welcome to {{ project_name }} Documentation</h2>
                <p style="color: var(--text-muted); max-width: 600px; margin: 0 auto 2rem;">
                    Please select a module from the sidebar to view its detailed documentation.
                </p>
                <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1rem; text-align: left;">
                    {% for mod in modules | sort(attribute='name') %}
                    <a href="modules/{{ mod.original_name }}.html" class="item" style="text-decoration: none; color: inherit; display: block;">
                        <span class="item-name">{{ mod.name }}</span>
                    </a>
                    {% endfor %}
                </div>
            </div>
            {% endif %}
        </div>
    </main>
    <script src="{{ base_url }}search_index.js"></script>
    <script>
        const searchInput = document.getElementById('wikin-search');
        const resultsDropdown = document.getElementById('search-results');
        const sections = document.querySelectorAll('.doc-section');
        const sidebarItems = document.querySelectorAll('#sidebar-list li');
        
        const base_url = "{{ base_url }}";
        const multipage = {{ 'true' if multipage else 'false' }};
        let modulesLoaded = false;
        let loadingPromise = null;

        function highlightMatch(text, query) {
            if (!query) return text;
            const regex = new RegExp(`(${query.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\\\\\\\$&")})`, 'gi');
            return text.replace(regex, '<span class="highlight">$1</span>');
        }

        async function loadAllModules() {
            if (modulesLoaded) return;
            if (loadingPromise) return loadingPromise;

            const manifest = window.WIKIN_MANIFEST;
            if (!manifest || !multipage) {
                modulesLoaded = true;
                return;
            }

            loadingPromise = Promise.all(manifest.modules.map(mod => {
                return new Promise((resolve) => {
                    const script = document.createElement('script');
                    script.src = `${base_url}modules/${mod.original_name}.data.js`;
                    script.onload = resolve;
                    script.onerror = resolve; // Continue even if one fails
                    document.head.appendChild(script);
                });
            })).then(() => {
                modulesLoaded = true;
            });

            return loadingPromise;
        }

        async function performGlobalSearch(query) {
            await loadAllModules();
            
            let searchIndex = window.WIKIN_SEARCH_INDEX;
            const manifest = window.WIKIN_MANIFEST;

            // If multipage, construct searchIndex from window.WIKIN_MODULE_... variables
            if (multipage && manifest) {
                searchIndex = {
                    modules: manifest.modules.map(m => {
                        const varName = `WIKIN_MODULE_${m.original_name.replace(/\./g, '_')}`;
                        return window[varName];
                    }).filter(m => !!m)
                };
            }

            if (!searchIndex || !query) {
                resultsDropdown.style.display = 'none';
                return;
            }

            const results = [];
            const q = query.toLowerCase();

            searchIndex.modules.forEach(mod => {
                const modId = mod.original_name.replace(/\./g, '-');
                const modUrl = multipage ? `${base_url}modules/${mod.original_name}.html` : `#${modId}`;
                
                // Check module
                if (mod.name.toLowerCase().includes(q) || (mod.docstring && mod.docstring.toLowerCase().includes(q))) {
                    results.push({
                        type: 'module',
                        name: mod.name,
                        module: mod.name,
                        url: modUrl,
                        score: mod.name.toLowerCase().includes(q) ? 10 : 1
                    });
                }

                // Check classes
                mod.classes.forEach(cls => {
                    const clsId = `${modId}-${cls.name}`;
                    const clsUrl = `${modUrl}#${clsId}`;
                    if (cls.name.toLowerCase().includes(q) || (cls.docstring && cls.docstring.toLowerCase().includes(q))) {
                        results.push({
                            type: 'class',
                            name: cls.name,
                            module: mod.name,
                            url: clsUrl,
                            score: cls.name.toLowerCase().includes(q) ? 8 : 1
                        });
                    }
                    if (cls.methods) {
                        cls.methods.forEach(method => {
                            const methodId = `${clsId}-${method.name}`;
                            if (method.name.toLowerCase().includes(q) || (method.docstring && method.docstring.toLowerCase().includes(q))) {
                                results.push({
                                    type: 'method',
                                    name: `${cls.name}.${method.name}`,
                                    module: mod.name,
                                    url: `${modUrl}#${methodId}`,
                                    score: method.name.toLowerCase().includes(q) ? 6 : 1
                                });
                            }
                        });
                    }
                });

                // Check functions
                mod.functions.forEach(func => {
                    const funcId = `${modId}-${func.name}`;
                    if (func.name.toLowerCase().includes(q) || (func.docstring && func.docstring.toLowerCase().includes(q))) {
                        results.push({
                            type: 'function',
                            name: func.name,
                            module: mod.name,
                            url: `${modUrl}#${funcId}`,
                            score: func.name.toLowerCase().includes(q) ? 7 : 1
                        });
                    }
                });

                // Check variables
                mod.variables.forEach(var_ => {
                    const varId = `${modId}-${var_.name}`;
                    if (var_.name.toLowerCase().includes(q) || (var_.docstring && var_.docstring.toLowerCase().includes(q))) {
                        results.push({
                            type: 'variable',
                            name: var_.name,
                            module: mod.name,
                            url: `${modUrl}#${varId}`,
                            score: var_.name.toLowerCase().includes(q) ? 5 : 1
                        });
                    }
                });
            });

            // Sort by score
            results.sort((a, b) => b.score - a.score);
            renderResults(results.slice(0, 15), query);
        }

        function renderResults(results, query) {
            if (results.length === 0) {
                resultsDropdown.innerHTML = '<div style="padding: 1rem; color: var(--text-muted); text-align: center;">No global matches found</div>';
                resultsDropdown.style.display = 'block';
                return;
            }

            resultsDropdown.innerHTML = '';
            results.forEach(res => {
                const div = document.createElement('a');
                div.className = 'search-result-item';
                div.href = res.url;
                div.innerHTML = `
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2px;">
                        <span class="search-result-type">${res.type}</span>
                        <span class="search-result-module" style="margin-bottom: 0;">${res.module}</span>
                    </div>
                    <span class="search-result-name">${highlightMatch(res.name, query)}</span>
                `;
                div.onclick = () => {
                    resultsDropdown.style.display = 'none';
                    searchInput.value = '';
                };
                resultsDropdown.appendChild(div);
            });
            resultsDropdown.style.display = 'block';
        }

        searchInput.addEventListener('focus', () => {
            loadAllModules();
        });

        searchInput.addEventListener('input', (e) => {
            const query = e.target.value.toLowerCase().trim();
            if (query.length < 2) {
                resultsDropdown.style.display = 'none';
                return;
            }
            performGlobalSearch(query);
        });

        // Hide results when clicking outside
        document.addEventListener('click', (e) => {
            if (!searchInput.contains(e.target) && !resultsDropdown.contains(e.target)) {
                resultsDropdown.style.display = 'none';
            }
        });
    </script>
</body>
</html>
"""

class WikinGenerator:
    """
    Generates a premium-look HTML documentation from parsed module data.
    """
    def __init__(self, project_name: str, version: str):
        """
        Initialize the generator with project metadata and configuration.
        """
        self.project_name = project_name
        self.version = version
        self.config = {}
        self.links = {}
        self.multipage = False
        
        if tomllib:
            config_path = os.path.join(os.getcwd(), "docs", ".wikinconfig")
            if os.path.exists(config_path):
                try:
                    with open(config_path, "rb") as f:
                        self.config = tomllib.load(f)
                        self.links = self.config.get("links", {})
                        self.multipage = self.config.get("main", {}).get("multipage", False)
                except Exception as e:
                    print(f"Warning: Failed to load .wikinconfig: {e}")
        
        # Setup Jinja2 environment
        self.env = jinja2.Environment(
            loader=jinja2.BaseLoader(),
            autoescape=True
        )
        self.env.filters['markdown'] = lambda x: markdown.markdown(x) if x else ""
        self.template = self.env.from_string(HTML_TEMPLATE)

    def generate(self, modules: List[ModuleDoc], current_module: ModuleDoc = None) -> str:
        """
        Transforms a list of ModuleDoc objects into an HTML string.
        In multipage mode, handles relative paths for modules and index.
        """
        content_modules = [current_module] if current_module else modules
        if not current_module and self.multipage:
            # Landing page (index.html)
            content_modules = [] # Don't show modules directly on landing page if multipage
            base_url = "./"
            module_prefix = "modules/"
        elif current_module and self.multipage:
            # Individual module page
            base_url = "../"
            module_prefix = "./"
        else:
            # Single page mode
            base_url = "./"
            module_prefix = "#"
            pass

        return self.template.render(
            project_name=self.project_name,
            version=self.version,
            modules=modules,
            content_modules=content_modules,
            links=self.links,
            multipage=self.multipage,
            current_module=current_module,
            base_url=base_url,
            module_prefix=module_prefix
        )

    def get_search_data(self, modules: List[ModuleDoc]) -> dict:
        """
        Serializes all module data into a dictionary for global search.
        """
        import dataclasses
        return {
            "project_name": self.project_name,
            "version": self.version,
            "modules": [dataclasses.asdict(m) for m in modules]
        }

    def save(self, html: str, output_path: str):
        """
        Saves the generated HTML to the specified file path.
        """
        os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(html)
        print(f"Documentation saved to {output_path}")
