import json
import logging
import re
from app.services.llm import call_llm_routed

logger = logging.getLogger(__name__)


REFERENCE_SECTIONS = [
    {"key": "glossary", "label": "Glossary & Dictionary", "description": "A-Z terms and definitions", "min_entries": 20},
    {"key": "history", "label": "History & Origins", "description": "How this field evolved", "min_entries": 5},
    {"key": "getting_started", "label": "Getting Started Guide", "description": "Beginner's roadmap", "min_entries": 8},
    {"key": "pro_tips", "label": "Pro Tips & Strategies", "description": "Expert-level techniques", "min_entries": 10},
    {"key": "equipment", "label": "Equipment & Gear Guide", "description": "Reviews and recommendations", "min_entries": 8},
    {"key": "statistics", "label": "Industry Statistics", "description": "Key numbers and market data", "min_entries": 8},
    {"key": "formulas", "label": "Common Calculations", "description": "Quick-reference formulas and math", "min_entries": 5},
    {"key": "regulations", "label": "Regulatory & Compliance", "description": "Rules, licenses, requirements", "min_entries": 5},
    {"key": "community", "label": "Community Resources", "description": "Associations, forums, events", "min_entries": 8},
    {"key": "faq", "label": "Frequently Asked Questions", "description": "Common questions answered", "min_entries": 10},
    {"key": "media", "label": "Video & Media Resources", "description": "Curated educational content", "min_entries": 5},
    {"key": "checklists", "label": "Templates & Checklists", "description": "Downloadable practical tools", "min_entries": 3},
]

SECTION_ICONS = {
    "glossary": "📖",
    "history": "🏛️",
    "getting_started": "🚀",
    "pro_tips": "💡",
    "equipment": "🛠️",
    "statistics": "📊",
    "formulas": "🧮",
    "regulations": "⚖️",
    "community": "🤝",
    "faq": "❓",
    "media": "🎬",
    "checklists": "✅",
}

DEFAULT_BRAND_COLORS = {
    "primary": "#4F46E5",
    "secondary": "#7C3AED",
    "accent": "#06B6D4",
}


def _safe_colors(brand_colors: dict = None) -> dict:
    if not brand_colors:
        return DEFAULT_BRAND_COLORS.copy()
    return {
        "primary": brand_colors.get("primary", brand_colors.get("color_primary", DEFAULT_BRAND_COLORS["primary"])),
        "secondary": brand_colors.get("secondary", brand_colors.get("color_secondary", DEFAULT_BRAND_COLORS["secondary"])),
        "accent": brand_colors.get("accent", brand_colors.get("color_accent", DEFAULT_BRAND_COLORS["accent"])),
    }


def _build_niche_context_block(niche_name: str, niche_data: dict) -> str:
    if not niche_data:
        return f'Niche: "{niche_name}"'
    parts = [f'Niche Name: {niche_name}']
    if niche_data.get("description"):
        parts.append(f'Description: {niche_data["description"]}')
    if niche_data.get("target_audience"):
        parts.append(f'Target Audience: {niche_data["target_audience"]}')
    if niche_data.get("monetization_model"):
        parts.append(f'Monetization Model: {niche_data["monetization_model"]}')
    if niche_data.get("affiliate_programs"):
        parts.append(f'Affiliate Programs: {json.dumps(niche_data["affiliate_programs"])}')
    if niche_data.get("synopsis"):
        parts.append(f'Synopsis: {niche_data["synopsis"]}')
    if niche_data.get("valuation_band"):
        parts.append(f'Valuation Band: {niche_data["valuation_band"]}')
    if niche_data.get("score"):
        parts.append(f'Viability Score: {niche_data["score"]}/10')
    return "\n".join(parts)


def _parse_json_response(response: str) -> dict:
    cleaned = response.strip()
    if cleaned.startswith("```"):
        cleaned = cleaned.split("\n", 1)[-1].rsplit("```", 1)[0].strip()
    start = cleaned.find("{")
    end = cleaned.rfind("}") + 1
    if start >= 0 and end > start:
        cleaned = cleaned[start:end]
    try:
        return json.loads(cleaned)
    except json.JSONDecodeError:
        cleaned = re.sub(r',\s*([}\]])', r'\1', cleaned)
        try:
            return json.loads(cleaned)
        except json.JSONDecodeError:
            logger.error(f"Failed to parse JSON response: {response[:500]}")
            return {}


def generate_reference_outline(niche_name: str, niche_data: dict) -> dict:
    niche_context = _build_niche_context_block(niche_name, niche_data)
    sections_list = "\n".join(
        [f'- key: "{s["key"]}", label: "{s["label"]}", description: "{s["description"]}", min_entries: {s["min_entries"]}'
         for s in REFERENCE_SECTIONS]
    )

    system_prompt = (
        "You are a world-class niche research analyst and encyclopedia architect. "
        "You specialize in creating comprehensive, authoritative reference libraries "
        "that demonstrate deep industry expertise. You never produce generic content — "
        "every recommendation is specific, researched, and tailored to the exact niche. "
        "Always respond with valid JSON."
    )

    prompt = f"""Create a detailed reference library outline for the following niche business.

NICHE CONTEXT:
{niche_context}

AVAILABLE SECTIONS:
{sections_list}

TASK:
Analyze the niche and determine which sections (8-12) are most relevant and valuable. For each selected section, provide:
1. Whether it should be included (true/false)
2. A relevance score (1-10) for this specific niche
3. A list of 5-15 specific subtopics/entries that should be covered
4. A brief rationale for why this section matters for this niche

Think about what someone entering this niche would NEED to know. What would save them weeks of research? What insider knowledge would make them look like an expert?

Return JSON in this exact format:
{{
    "niche_name": "{niche_name}",
    "library_title": "The Complete [Niche] Reference Library",
    "library_subtitle": "A one-line description of the library's value",
    "total_sections": 10,
    "sections": {{
        "glossary": {{
            "included": true,
            "relevance": 9,
            "rationale": "Why this section matters for this niche",
            "subtopics": ["Term 1", "Term 2", "Term 3", "..."]
        }},
        "history": {{
            "included": true,
            "relevance": 7,
            "rationale": "...",
            "subtopics": ["Topic 1", "Topic 2", "..."]
        }}
    }}
}}

Include ALL 12 section keys in your response. Set "included": false for sections that are not relevant. Ensure at least 8 sections are included.

CRITICAL: The subtopics must be SPECIFIC to the "{niche_name}" niche. Not generic business subtopics. Real, industry-specific terms, concepts, tools, regulations, and resources that demonstrate deep domain expertise."""

    try:
        response = call_llm_routed("site_copy", prompt, system_prompt, max_tokens=8192)
        outline = _parse_json_response(response)
        if not outline or "sections" not in outline:
            logger.warning(f"Outline generation returned incomplete data for {niche_name}, using defaults")
            outline = _build_default_outline(niche_name)
        included_count = sum(1 for s in outline.get("sections", {}).values() if s.get("included"))
        if included_count < 8:
            for section in REFERENCE_SECTIONS:
                key = section["key"]
                if key not in outline.get("sections", {}):
                    outline.setdefault("sections", {})[key] = {
                        "included": True,
                        "relevance": 5,
                        "rationale": f"Standard reference section for {niche_name}",
                        "subtopics": [],
                    }
                elif not outline["sections"][key].get("included"):
                    if included_count < 8:
                        outline["sections"][key]["included"] = True
                        included_count += 1
        return outline
    except Exception as e:
        logger.error(f"Error generating reference outline for {niche_name}: {e}")
        return _build_default_outline(niche_name)


def _build_default_outline(niche_name: str) -> dict:
    sections = {}
    for s in REFERENCE_SECTIONS:
        sections[s["key"]] = {
            "included": True,
            "relevance": 7,
            "rationale": f"Essential reference content for {niche_name}",
            "subtopics": [],
        }
    return {
        "niche_name": niche_name,
        "library_title": f"The Complete {niche_name.replace('_', ' ').title()} Reference Library",
        "library_subtitle": f"Everything you need to know about {niche_name.replace('_', ' ')}",
        "total_sections": len(REFERENCE_SECTIONS),
        "sections": sections,
    }


def generate_reference_section(section_key: str, section_config: dict, niche_name: str, niche_data: dict, outline: dict) -> dict:
    niche_context = _build_niche_context_block(niche_name, niche_data)
    section_outline = outline.get("sections", {}).get(section_key, {})
    subtopics = section_outline.get("subtopics", [])
    subtopics_str = ", ".join(subtopics) if subtopics else "Generate appropriate subtopics"
    min_entries = section_config.get("min_entries", 5)

    section_specific_instructions = _get_section_instructions(section_key, niche_name, niche_data)

    system_prompt = (
        "You are a niche encyclopedia author with deep expertise across hundreds of industries. "
        "You produce content that reads like it was written by a 20-year veteran of the industry — "
        "specific, authoritative, practical, and packed with insider knowledge. "
        "Every entry must have real substance. No generic advice. No filler. "
        "If you mention a product, give the actual product name. If you cite a statistic, give a real number. "
        "If you reference a resource, give the actual name and where to find it. "
        "Always respond with valid JSON."
    )

    prompt = f"""Generate comprehensive reference content for the "{section_config['label']}" section of the {niche_name} Reference Library.

NICHE CONTEXT:
{niche_context}

SECTION: {section_config['label']}
SECTION DESCRIPTION: {section_config['description']}
SUGGESTED SUBTOPICS: {subtopics_str}
MINIMUM ENTRIES REQUIRED: {min_entries}

{section_specific_instructions}

QUALITY STANDARDS:
- Every entry must contain SPECIFIC, REAL information — not generic business advice
- Use actual industry terminology, real product names, real organization names
- Include actual numbers, statistics, prices, and measurements where relevant
- Content should demonstrate deep domain expertise in {niche_name}
- A reader should think "this person has been in the {niche_name} industry for years"
- Each entry should save the reader 15-30 minutes of independent research

Return JSON in this exact format:
{{
    "section_key": "{section_key}",
    "section_label": "{section_config['label']}",
    "section_description": "A rich 2-3 sentence description of this section for {niche_name}",
    "entry_count": {min_entries},
    "entries": [
        {{
            "term": "Entry Title/Term",
            "definition": "A clear, concise 1-2 sentence definition or summary",
            "details": "A detailed 3-8 sentence explanation with specific facts, examples, numbers, and practical advice. This is the expanded content shown when the user clicks to read more.",
            "tags": ["tag1", "tag2", "tag3"],
            "related_terms": ["Related Entry 1", "Related Entry 2"],
            "affiliate_opportunity": {{
                "has_opportunity": true,
                "program_name": "Amazon Associates / specific affiliate program",
                "product_category": "What type of product/service",
                "typical_commission": "5-15%",
                "recommendation": "Brief recommendation text"
            }},
            "pro_tip": "An insider tip or lesser-known fact (optional, include when relevant)",
            "source": "Citation or reference source (optional)"
        }}
    ]
}}

Generate at least {min_entries} entries. For the glossary section, generate at least 20 entries sorted A-Z.
CRITICAL: Return ONLY valid JSON. No markdown, no code fences."""

    try:
        response = call_llm_routed("site_copy", prompt, system_prompt, max_tokens=16384)
        section_data = _parse_json_response(response)
        if not section_data or "entries" not in section_data:
            logger.warning(f"Section generation returned no entries for {section_key} in {niche_name}")
            section_data = {
                "section_key": section_key,
                "section_label": section_config["label"],
                "section_description": section_config["description"],
                "entry_count": 0,
                "entries": [],
            }
        for entry in section_data.get("entries", []):
            if "term" not in entry:
                entry["term"] = entry.get("title", entry.get("name", "Untitled"))
            if "definition" not in entry:
                entry["definition"] = entry.get("summary", entry.get("description", ""))
            if "details" not in entry:
                entry["details"] = entry.get("content", entry.get("body", entry.get("explanation", "")))
            if "tags" not in entry:
                entry["tags"] = []
            if "related_terms" not in entry:
                entry["related_terms"] = []
            if "affiliate_opportunity" not in entry:
                entry["affiliate_opportunity"] = {"has_opportunity": False}
        section_data["entry_count"] = len(section_data.get("entries", []))
        return section_data
    except Exception as e:
        logger.error(f"Error generating section {section_key} for {niche_name}: {e}")
        return {
            "section_key": section_key,
            "section_label": section_config["label"],
            "section_description": section_config["description"],
            "entry_count": 0,
            "entries": [],
            "error": str(e),
        }


def _get_section_instructions(section_key: str, niche_name: str, niche_data: dict) -> str:
    affiliates = niche_data.get("affiliate_programs", []) if niche_data else []
    affiliates_str = ", ".join(affiliates) if affiliates else "research and suggest relevant affiliate programs"

    instructions = {
        "glossary": f"""GLOSSARY-SPECIFIC INSTRUCTIONS:
- Sort entries alphabetically A-Z
- Include both beginner and advanced terms
- Cover technical jargon, slang, abbreviations, and industry-specific terminology
- Each definition should be precise enough to use in a professional context
- Include pronunciation guides for uncommon terms
- Cross-reference related terms extensively""",

        "history": f"""HISTORY-SPECIFIC INSTRUCTIONS:
- Cover the origin story and key milestones chronologically
- Include specific dates, names of founders/pioneers, and locations
- Highlight pivotal moments that shaped the industry
- Connect historical context to current industry state
- Include interesting facts and lesser-known history""",

        "getting_started": f"""GETTING STARTED-SPECIFIC INSTRUCTIONS:
- Structure as a step-by-step roadmap from complete beginner to competent practitioner
- Include estimated time and cost for each step
- Mention specific resources, courses, or certifications by name
- Address common beginner mistakes and how to avoid them
- Include a "quick start" path for those who want to begin immediately""",

        "pro_tips": f"""PRO TIPS-SPECIFIC INSTRUCTIONS:
- Focus on expert-level strategies that differentiate professionals from amateurs
- Include specific techniques with step-by-step instructions
- Reference named strategies, frameworks, or methodologies used by industry leaders
- Include "the thing most people get wrong" insights
- Each tip should provide measurable improvement or competitive advantage""",

        "equipment": f"""EQUIPMENT-SPECIFIC INSTRUCTIONS:
- Include specific product names, models, and brands
- Provide price ranges (budget, mid-range, professional)
- Include affiliate opportunity data for each item: program name ({affiliates_str}), typical commission rates
- Rate items on value-for-money, durability, and performance
- Include "what to buy first" prioritization
- Mention where to buy (specific retailers, online stores)""",

        "statistics": f"""STATISTICS-SPECIFIC INSTRUCTIONS:
- Include actual numbers: market size, growth rates, average revenues, participation rates
- Cite sources where possible (industry reports, government data, trade associations)
- Include year of data for currency
- Cover both macro (industry-wide) and micro (individual business) statistics
- Include trend data showing growth or decline
- Make numbers actionable — explain what they mean for someone in this niche""",

        "formulas": f"""FORMULAS-SPECIFIC INSTRUCTIONS:
- Include the actual mathematical formula with variable explanations
- Provide worked examples with real numbers
- Cover pricing formulas, conversion rates, capacity calculations, ROI formulas
- Include industry-standard benchmarks for formula inputs
- Each formula should solve a real problem the target audience faces""",

        "regulations": f"""REGULATIONS-SPECIFIC INSTRUCTIONS:
- Cover federal, state, and local regulations where applicable
- Include specific license names, certifying bodies, and costs
- Mention insurance requirements with typical coverage amounts
- Reference specific laws, codes, or standards by name and number
- Include compliance checklists and renewal timelines
- Note regional variations (US-focused unless niche is international)""",

        "community": f"""COMMUNITY-SPECIFIC INSTRUCTIONS:
- List specific associations, organizations, and trade groups by name with URLs
- Include online communities (subreddits, forums, Facebook groups, Discord servers)
- List major industry events, conferences, and trade shows with typical dates
- Include networking opportunities and mentorship programs
- Reference industry publications, podcasts, and newsletters by name""",

        "faq": f"""FAQ-SPECIFIC INSTRUCTIONS:
- Address the questions that are ACTUALLY most frequently asked (not what you think should be asked)
- Include both beginner questions and advanced questions
- Provide thorough, authoritative answers (not one-liners)
- Include "related questions" for each FAQ
- Address misconceptions and common mistakes
- Include cost-related questions that real customers/practitioners ask""",

        "media": f"""MEDIA-SPECIFIC INSTRUCTIONS:
- Reference specific YouTube channels, podcasts, and online courses by name
- Include estimated course durations and whether free or paid (with prices)
- Rate resources by quality and relevance
- Include book recommendations with authors and ISBN/edition info
- Reference specific tutorial series or educational content creators
- Include documentary or educational video recommendations""",

        "checklists": f"""CHECKLISTS-SPECIFIC INSTRUCTIONS:
- Create practical, actionable checklists that someone could print and use immediately
- Include startup checklists, daily operation checklists, and maintenance checklists
- Each checklist item should be specific and actionable (not vague)
- Include estimated time for completing each checklist
- Reference specific tools, forms, or resources needed for each item
- Include regulatory compliance checklists where applicable""",
    }
    return instructions.get(section_key, "")


def generate_full_reference_library(niche_name: str, niche_data: dict, progress_callback=None) -> dict:
    if progress_callback:
        progress_callback("Generating reference library outline...", 0, 1)

    outline = generate_reference_outline(niche_name, niche_data)
    library = {
        "niche_name": niche_name,
        "library_title": outline.get("library_title", f"The Complete {niche_name.replace('_', ' ').title()} Reference Library"),
        "library_subtitle": outline.get("library_subtitle", ""),
        "sections": {},
        "metadata": {
            "total_entries": 0,
            "total_sections": 0,
            "section_order": [],
        },
    }

    included_sections = []
    for section_config in REFERENCE_SECTIONS:
        key = section_config["key"]
        section_outline = outline.get("sections", {}).get(key, {})
        if section_outline.get("included", True):
            included_sections.append((key, section_config, section_outline))

    included_sections.sort(key=lambda x: x[2].get("relevance", 5), reverse=True)
    total_sections = len(included_sections)

    for idx, (key, section_config, section_outline) in enumerate(included_sections):
        if progress_callback:
            progress_callback(
                f"Generating {section_config['label']}... ({idx + 1}/{total_sections})",
                idx + 1,
                total_sections + 1,
            )

        section_data = generate_reference_section(key, section_config, niche_name, niche_data, outline)
        section_data["icon"] = SECTION_ICONS.get(key, "📄")
        section_data["relevance"] = section_outline.get("relevance", 5)
        library["sections"][key] = section_data
        library["metadata"]["total_entries"] += section_data.get("entry_count", 0)
        library["metadata"]["section_order"].append(key)

    library["metadata"]["total_sections"] = len(library["sections"])

    if progress_callback:
        progress_callback(
            f"Reference library complete! {library['metadata']['total_entries']} entries across {library['metadata']['total_sections']} sections.",
            total_sections + 1,
            total_sections + 1,
        )

    return library


def render_reference_html(library: dict, brand_colors: dict = None) -> str:
    colors = _safe_colors(brand_colors)
    primary = colors["primary"]
    secondary = colors["secondary"]
    accent = colors["accent"]

    title = library.get("library_title", "Reference Library")
    subtitle = library.get("library_subtitle", "")
    niche_name = library.get("niche_name", "")
    sections = library.get("sections", {})
    section_order = library.get("metadata", {}).get("section_order", list(sections.keys()))
    total_entries = library.get("metadata", {}).get("total_entries", 0)

    nav_items_html = ""
    sections_html = ""

    for key in section_order:
        section = sections.get(key)
        if not section:
            continue
        label = section.get("section_label", key.replace("_", " ").title())
        icon = section.get("icon", SECTION_ICONS.get(key, "📄"))
        entry_count = section.get("entry_count", 0)
        entries = section.get("entries", [])
        section_desc = section.get("section_description", "")

        nav_items_html += f"""
            <a href="#section-{key}" class="nav-item" data-section="{key}" onclick="scrollToSection('{key}')">
                <span class="nav-icon">{icon}</span>
                <span class="nav-label">{label}</span>
                <span class="nav-badge">{entry_count}</span>
            </a>"""

        letter_nav_html = ""
        if key == "glossary" and entries:
            letters = sorted(set(e.get("term", "?")[0].upper() for e in entries if e.get("term")))
            letter_nav_html = '<div class="letter-nav">'
            for letter in letters:
                letter_nav_html += f'<a href="#" class="letter-link" onclick="filterByLetter(\'{key}\', \'{letter}\'); return false;">{letter}</a>'
            letter_nav_html += '<a href="#" class="letter-link active" onclick="filterByLetter(\'{key}\', \'all\'); return false;">All</a>'
            letter_nav_html += '</div>'

        entries_html = ""
        for i, entry in enumerate(entries):
            term = _escape_html(entry.get("term", ""))
            definition = _escape_html(entry.get("definition", ""))
            details = _escape_html(entry.get("details", ""))
            tags = entry.get("tags", [])
            related = entry.get("related_terms", [])
            affiliate = entry.get("affiliate_opportunity", {})
            pro_tip = _escape_html(entry.get("pro_tip", ""))
            source = _escape_html(entry.get("source", ""))
            first_letter = term[0].upper() if term else ""

            tags_html = ""
            for tag in tags[:5]:
                tags_html += f'<span class="tag-badge" onclick="searchByTag(\'{_escape_html(tag)}\')">{_escape_html(tag)}</span>'

            related_html = ""
            if related:
                related_html = '<div class="related-terms"><span class="related-label">Related:</span> '
                for r in related[:4]:
                    related_html += f'<a href="#" class="related-link" onclick="searchByTerm(\'{_escape_html(r)}\'); return false;">{_escape_html(r)}</a>'
                related_html += '</div>'

            affiliate_html = ""
            if affiliate.get("has_opportunity"):
                prog = _escape_html(affiliate.get("program_name", ""))
                cat = _escape_html(affiliate.get("product_category", ""))
                comm = _escape_html(affiliate.get("typical_commission", ""))
                rec = _escape_html(affiliate.get("recommendation", ""))
                affiliate_html = f"""
                    <div class="affiliate-callout">
                        <div class="affiliate-header">
                            <span class="affiliate-icon">💰</span>
                            <span class="affiliate-label">Affiliate Opportunity</span>
                        </div>
                        <div class="affiliate-body">
                            {f'<div class="affiliate-detail"><strong>Program:</strong> {prog}</div>' if prog else ''}
                            {f'<div class="affiliate-detail"><strong>Category:</strong> {cat}</div>' if cat else ''}
                            {f'<div class="affiliate-detail"><strong>Commission:</strong> {comm}</div>' if comm else ''}
                            {f'<div class="affiliate-detail"><strong>Recommendation:</strong> {rec}</div>' if rec else ''}
                        </div>
                    </div>"""

            pro_tip_html = ""
            if pro_tip:
                pro_tip_html = f"""
                    <div class="pro-tip">
                        <span class="pro-tip-icon">⚡</span>
                        <span class="pro-tip-text">{pro_tip}</span>
                    </div>"""

            source_html = ""
            if source:
                source_html = f'<div class="entry-source">Source: {source}</div>'

            entries_html += f"""
                <div class="entry-card" data-term="{term.lower()}" data-tags="{' '.join(t.lower() for t in tags)}" data-letter="{first_letter}" data-section="{key}">
                    <div class="entry-header" onclick="toggleEntry(this)">
                        <div class="entry-title-row">
                            <h3 class="entry-term">{term}</h3>
                            <div class="entry-tags">{tags_html}</div>
                        </div>
                        <p class="entry-definition">{definition}</p>
                        <span class="expand-icon">▼</span>
                    </div>
                    <div class="entry-body">
                        <div class="entry-details">{details}</div>
                        {pro_tip_html}
                        {affiliate_html}
                        {related_html}
                        {source_html}
                    </div>
                </div>"""

        sections_html += f"""
            <section id="section-{key}" class="library-section" data-section-key="{key}">
                <div class="section-header">
                    <span class="section-icon">{icon}</span>
                    <div class="section-title-group">
                        <h2 class="section-title">{label}</h2>
                        <p class="section-description">{_escape_html(section_desc)}</p>
                    </div>
                    <span class="section-count">{entry_count} entries</span>
                </div>
                {letter_nav_html}
                <div class="entries-container" id="entries-{key}">
                    {entries_html}
                </div>
            </section>"""

    html = f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{_escape_html(title)}</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <style>
        :root {{
            --color-primary: {primary};
            --color-secondary: {secondary};
            --color-accent: {accent};
            --bg-primary: #0f172a;
            --bg-secondary: #1e293b;
            --bg-card: rgba(30, 41, 59, 0.8);
            --bg-card-hover: rgba(51, 65, 85, 0.9);
            --text-primary: #f1f5f9;
            --text-secondary: #94a3b8;
            --text-muted: #64748b;
            --border-color: rgba(148, 163, 184, 0.1);
            --glass-bg: rgba(15, 23, 42, 0.6);
            --glass-border: rgba(148, 163, 184, 0.15);
        }}
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        html {{ scroll-behavior: smooth; }}
        body {{
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: var(--bg-primary);
            color: var(--text-primary);
            line-height: 1.6;
            min-height: 100vh;
        }}
        .layout {{
            display: flex;
            min-height: 100vh;
        }}
        .sidebar {{
            width: 280px;
            background: var(--glass-bg);
            backdrop-filter: blur(20px);
            border-right: 1px solid var(--glass-border);
            position: fixed;
            top: 0;
            left: 0;
            height: 100vh;
            overflow-y: auto;
            z-index: 100;
            transition: transform 0.3s ease;
        }}
        .sidebar-header {{
            padding: 24px 20px;
            border-bottom: 1px solid var(--border-color);
        }}
        .sidebar-title {{
            font-size: 1.1rem;
            font-weight: 700;
            color: var(--text-primary);
            margin-bottom: 4px;
        }}
        .sidebar-subtitle {{
            font-size: 0.75rem;
            color: var(--text-muted);
        }}
        .sidebar-stats {{
            display: flex;
            gap: 12px;
            padding: 12px 20px;
            border-bottom: 1px solid var(--border-color);
        }}
        .stat-pill {{
            font-size: 0.7rem;
            color: var(--text-secondary);
            background: rgba(148, 163, 184, 0.1);
            padding: 4px 10px;
            border-radius: 20px;
        }}
        .sidebar-nav {{
            padding: 12px 0;
        }}
        .nav-item {{
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 10px 20px;
            color: var(--text-secondary);
            text-decoration: none;
            font-size: 0.85rem;
            transition: all 0.2s;
            cursor: pointer;
            border-left: 3px solid transparent;
        }}
        .nav-item:hover, .nav-item.active {{
            color: var(--text-primary);
            background: rgba(148, 163, 184, 0.08);
            border-left-color: var(--color-primary);
        }}
        .nav-icon {{ font-size: 1rem; width: 24px; text-align: center; }}
        .nav-label {{ flex: 1; }}
        .nav-badge {{
            font-size: 0.65rem;
            background: var(--color-primary);
            color: white;
            padding: 2px 7px;
            border-radius: 10px;
            font-weight: 600;
        }}
        .main-content {{
            margin-left: 280px;
            flex: 1;
            min-width: 0;
        }}
        .content-header {{
            background: linear-gradient(135deg, var(--color-primary), var(--color-secondary));
            padding: 48px 40px;
            position: relative;
            overflow: hidden;
        }}
        .content-header::before {{
            content: '';
            position: absolute;
            top: -50%;
            right: -20%;
            width: 60%;
            height: 200%;
            background: radial-gradient(ellipse, rgba(255,255,255,0.05) 0%, transparent 70%);
            pointer-events: none;
        }}
        .header-title {{
            font-size: 2.2rem;
            font-weight: 800;
            color: white;
            margin-bottom: 8px;
            position: relative;
        }}
        .header-subtitle {{
            font-size: 1rem;
            color: rgba(255,255,255,0.75);
            max-width: 600px;
            position: relative;
        }}
        .search-container {{
            position: sticky;
            top: 0;
            z-index: 50;
            padding: 16px 40px;
            background: var(--bg-primary);
            border-bottom: 1px solid var(--border-color);
            backdrop-filter: blur(10px);
        }}
        .search-wrapper {{
            position: relative;
            max-width: 600px;
        }}
        .search-input {{
            width: 100%;
            padding: 12px 16px 12px 44px;
            background: var(--bg-secondary);
            border: 1px solid var(--glass-border);
            border-radius: 12px;
            color: var(--text-primary);
            font-size: 0.9rem;
            outline: none;
            transition: border-color 0.2s;
        }}
        .search-input:focus {{
            border-color: var(--color-primary);
        }}
        .search-input::placeholder {{ color: var(--text-muted); }}
        .search-icon {{
            position: absolute;
            left: 14px;
            top: 50%;
            transform: translateY(-50%);
            color: var(--text-muted);
            font-size: 1.1rem;
        }}
        .search-results-count {{
            position: absolute;
            right: 14px;
            top: 50%;
            transform: translateY(-50%);
            color: var(--text-muted);
            font-size: 0.75rem;
        }}
        .content-body {{
            padding: 32px 40px;
            max-width: 960px;
        }}
        .library-section {{
            margin-bottom: 48px;
        }}
        .section-header {{
            display: flex;
            align-items: center;
            gap: 16px;
            margin-bottom: 24px;
            padding-bottom: 16px;
            border-bottom: 2px solid var(--color-primary);
        }}
        .section-icon {{
            font-size: 2rem;
            width: 48px;
            height: 48px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: rgba(79, 70, 229, 0.1);
            border-radius: 12px;
            flex-shrink: 0;
        }}
        .section-title-group {{ flex: 1; }}
        .section-title {{
            font-size: 1.5rem;
            font-weight: 700;
            color: var(--text-primary);
        }}
        .section-description {{
            font-size: 0.85rem;
            color: var(--text-secondary);
            margin-top: 2px;
        }}
        .section-count {{
            font-size: 0.75rem;
            color: var(--color-accent);
            background: rgba(6, 182, 212, 0.1);
            padding: 4px 12px;
            border-radius: 20px;
            font-weight: 600;
            white-space: nowrap;
        }}
        .letter-nav {{
            display: flex;
            flex-wrap: wrap;
            gap: 4px;
            margin-bottom: 20px;
        }}
        .letter-link {{
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            background: var(--bg-secondary);
            border: 1px solid var(--glass-border);
            border-radius: 8px;
            color: var(--text-secondary);
            text-decoration: none;
            font-size: 0.8rem;
            font-weight: 600;
            transition: all 0.2s;
            cursor: pointer;
        }}
        .letter-link:hover, .letter-link.active {{
            background: var(--color-primary);
            color: white;
            border-color: var(--color-primary);
        }}
        .entry-card {{
            background: var(--bg-card);
            backdrop-filter: blur(10px);
            border: 1px solid var(--glass-border);
            border-radius: 12px;
            margin-bottom: 12px;
            overflow: hidden;
            transition: all 0.2s;
        }}
        .entry-card:hover {{
            border-color: rgba(79, 70, 229, 0.3);
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
        }}
        .entry-card.hidden {{ display: none; }}
        .entry-header {{
            padding: 16px 20px;
            cursor: pointer;
            position: relative;
            user-select: none;
        }}
        .entry-title-row {{
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            gap: 12px;
            margin-bottom: 6px;
        }}
        .entry-term {{
            font-size: 1.05rem;
            font-weight: 700;
            color: var(--text-primary);
        }}
        .entry-tags {{
            display: flex;
            flex-wrap: wrap;
            gap: 4px;
            flex-shrink: 0;
        }}
        .tag-badge {{
            font-size: 0.65rem;
            color: var(--color-accent);
            background: rgba(6, 182, 212, 0.1);
            padding: 2px 8px;
            border-radius: 6px;
            cursor: pointer;
            transition: all 0.2s;
            white-space: nowrap;
        }}
        .tag-badge:hover {{
            background: rgba(6, 182, 212, 0.25);
        }}
        .entry-definition {{
            font-size: 0.85rem;
            color: var(--text-secondary);
            line-height: 1.5;
            padding-right: 30px;
        }}
        .expand-icon {{
            position: absolute;
            right: 20px;
            top: 18px;
            color: var(--text-muted);
            font-size: 0.7rem;
            transition: transform 0.3s;
        }}
        .entry-card.expanded .expand-icon {{
            transform: rotate(180deg);
        }}
        .entry-body {{
            display: none;
            padding: 0 20px 20px;
            border-top: 1px solid var(--border-color);
        }}
        .entry-card.expanded .entry-body {{
            display: block;
        }}
        .entry-details {{
            font-size: 0.9rem;
            color: var(--text-primary);
            line-height: 1.7;
            margin-top: 16px;
            white-space: pre-line;
        }}
        .pro-tip {{
            display: flex;
            align-items: flex-start;
            gap: 10px;
            margin-top: 16px;
            padding: 12px 16px;
            background: rgba(245, 158, 11, 0.08);
            border: 1px solid rgba(245, 158, 11, 0.2);
            border-radius: 8px;
        }}
        .pro-tip-icon {{ font-size: 1rem; flex-shrink: 0; }}
        .pro-tip-text {{
            font-size: 0.85rem;
            color: #fbbf24;
            font-style: italic;
        }}
        .affiliate-callout {{
            margin-top: 16px;
            padding: 14px 16px;
            background: linear-gradient(135deg, rgba(79, 70, 229, 0.08), rgba(124, 58, 237, 0.08));
            border: 1px solid rgba(79, 70, 229, 0.2);
            border-radius: 8px;
        }}
        .affiliate-header {{
            display: flex;
            align-items: center;
            gap: 8px;
            margin-bottom: 8px;
        }}
        .affiliate-icon {{ font-size: 1rem; }}
        .affiliate-label {{
            font-size: 0.75rem;
            font-weight: 700;
            color: var(--color-primary);
            text-transform: uppercase;
            letter-spacing: 0.05em;
        }}
        .affiliate-body {{ font-size: 0.82rem; color: var(--text-secondary); }}
        .affiliate-detail {{ margin-bottom: 3px; }}
        .affiliate-detail strong {{ color: var(--text-primary); }}
        .related-terms {{
            margin-top: 14px;
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 6px;
        }}
        .related-label {{
            font-size: 0.75rem;
            color: var(--text-muted);
            font-weight: 600;
        }}
        .related-link {{
            font-size: 0.75rem;
            color: var(--color-accent);
            text-decoration: none;
            padding: 2px 8px;
            background: rgba(6, 182, 212, 0.08);
            border-radius: 4px;
            transition: all 0.2s;
        }}
        .related-link:hover {{ background: rgba(6, 182, 212, 0.2); }}
        .entry-source {{
            margin-top: 12px;
            font-size: 0.72rem;
            color: var(--text-muted);
            font-style: italic;
        }}
        .mobile-menu-btn {{
            display: none;
            position: fixed;
            top: 16px;
            left: 16px;
            z-index: 200;
            width: 44px;
            height: 44px;
            background: var(--color-primary);
            border: none;
            border-radius: 10px;
            color: white;
            font-size: 1.3rem;
            cursor: pointer;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        }}
        .sidebar-overlay {{
            display: none;
            position: fixed;
            inset: 0;
            background: rgba(0,0,0,0.5);
            z-index: 90;
        }}
        @media (max-width: 768px) {{
            .mobile-menu-btn {{ display: flex; }}
            .sidebar {{
                transform: translateX(-100%);
                width: 260px;
            }}
            .sidebar.open {{ transform: translateX(0); }}
            .sidebar-overlay.open {{ display: block; }}
            .main-content {{ margin-left: 0; }}
            .content-header {{ padding: 60px 20px 32px; }}
            .header-title {{ font-size: 1.6rem; }}
            .search-container {{ padding: 12px 20px; }}
            .content-body {{ padding: 20px; }}
            .section-header {{ flex-wrap: wrap; }}
            .entry-title-row {{ flex-direction: column; }}
            .entry-tags {{ margin-top: 4px; }}
        }}
        @media print {{
            .sidebar, .mobile-menu-btn, .sidebar-overlay, .search-container {{ display: none !important; }}
            .main-content {{ margin-left: 0; }}
            .entry-body {{ display: block !important; }}
            .expand-icon {{ display: none; }}
            .entry-card {{ break-inside: avoid; page-break-inside: avoid; border: 1px solid #ccc; }}
            .content-header {{ background: none; color: black; padding: 20px 0; }}
            .header-title, .header-subtitle {{ color: black; }}
            body {{ background: white; color: black; }}
            .entry-term, .entry-details, .section-title {{ color: black; }}
            .entry-definition, .section-description {{ color: #555; }}
        }}
        .no-results {{
            text-align: center;
            padding: 60px 20px;
            color: var(--text-muted);
        }}
        .no-results-icon {{ font-size: 3rem; margin-bottom: 16px; }}
        .no-results-text {{ font-size: 1.1rem; }}
    </style>
</head>
<body>
    <button class="mobile-menu-btn" onclick="toggleSidebar()" aria-label="Menu">☰</button>
    <div class="sidebar-overlay" onclick="toggleSidebar()"></div>

    <div class="layout">
        <aside class="sidebar">
            <div class="sidebar-header">
                <div class="sidebar-title">{_escape_html(title)}</div>
                <div class="sidebar-subtitle">{_escape_html(niche_name.replace('_', ' ').title())}</div>
            </div>
            <div class="sidebar-stats">
                <span class="stat-pill">{total_entries} entries</span>
                <span class="stat-pill">{len(section_order)} sections</span>
            </div>
            <nav class="sidebar-nav">
                {nav_items_html}
            </nav>
        </aside>

        <main class="main-content">
            <div class="content-header">
                <h1 class="header-title">{_escape_html(title)}</h1>
                <p class="header-subtitle">{_escape_html(subtitle)}</p>
            </div>

            <div class="search-container">
                <div class="search-wrapper">
                    <span class="search-icon">🔍</span>
                    <input type="text" class="search-input" id="searchInput" placeholder="Search entries, tags, or topics..." oninput="handleSearch(this.value)">
                    <span class="search-results-count" id="searchCount"></span>
                </div>
            </div>

            <div class="content-body" id="contentBody">
                {sections_html}
                <div class="no-results" id="noResults" style="display:none;">
                    <div class="no-results-icon">🔍</div>
                    <div class="no-results-text">No entries match your search</div>
                </div>
            </div>
        </main>
    </div>

    <script>
        function toggleEntry(header) {{
            const card = header.closest('.entry-card');
            card.classList.toggle('expanded');
        }}

        function toggleSidebar() {{
            document.querySelector('.sidebar').classList.toggle('open');
            document.querySelector('.sidebar-overlay').classList.toggle('open');
        }}

        function scrollToSection(key) {{
            const el = document.getElementById('section-' + key);
            if (el) {{
                el.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
                document.querySelector('.nav-item[data-section="' + key + '"]')?.classList.add('active');
                if (window.innerWidth < 768) toggleSidebar();
            }}
        }}

        function handleSearch(query) {{
            const q = query.toLowerCase().trim();
            const cards = document.querySelectorAll('.entry-card');
            const sections = document.querySelectorAll('.library-section');
            let visible = 0;
            let total = cards.length;

            cards.forEach(card => {{
                if (!q) {{
                    card.classList.remove('hidden');
                    visible++;
                    return;
                }}
                const term = card.dataset.term || '';
                const tags = card.dataset.tags || '';
                const def = card.querySelector('.entry-definition')?.textContent?.toLowerCase() || '';
                const det = card.querySelector('.entry-details')?.textContent?.toLowerCase() || '';
                const match = term.includes(q) || tags.includes(q) || def.includes(q) || det.includes(q);
                card.classList.toggle('hidden', !match);
                if (match) visible++;
            }});

            sections.forEach(sec => {{
                const visibleCards = sec.querySelectorAll('.entry-card:not(.hidden)');
                sec.style.display = visibleCards.length === 0 && q ? 'none' : '';
            }});

            const countEl = document.getElementById('searchCount');
            const noResults = document.getElementById('noResults');
            if (q) {{
                countEl.textContent = visible + ' of ' + total;
                noResults.style.display = visible === 0 ? '' : 'none';
            }} else {{
                countEl.textContent = '';
                noResults.style.display = 'none';
            }}
        }}

        function filterByLetter(sectionKey, letter) {{
            const container = document.getElementById('entries-' + sectionKey);
            if (!container) return;
            const cards = container.querySelectorAll('.entry-card');
            const links = container.parentElement.querySelectorAll('.letter-link');
            links.forEach(l => l.classList.remove('active'));
            event.target?.classList.add('active');

            cards.forEach(card => {{
                if (letter === 'all') {{
                    card.classList.remove('hidden');
                }} else {{
                    const cl = card.dataset.letter || '';
                    card.classList.toggle('hidden', cl !== letter);
                }}
            }});
        }}

        function searchByTag(tag) {{
            const input = document.getElementById('searchInput');
            input.value = tag;
            handleSearch(tag);
            window.scrollTo({{ top: 0, behavior: 'smooth' }});
        }}

        function searchByTerm(term) {{
            const input = document.getElementById('searchInput');
            input.value = term;
            handleSearch(term);
            window.scrollTo({{ top: 0, behavior: 'smooth' }});
        }}

        const observer = new IntersectionObserver((entries) => {{
            entries.forEach(entry => {{
                if (entry.isIntersecting) {{
                    const key = entry.target.dataset.sectionKey;
                    document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
                    document.querySelector('.nav-item[data-section="' + key + '"]')?.classList.add('active');
                }}
            }});
        }}, {{ threshold: 0.3 }});

        document.querySelectorAll('.library-section').forEach(sec => observer.observe(sec));
    </script>
</body>
</html>"""

    return html


def _escape_html(text: str) -> str:
    if not text:
        return ""
    return (
        str(text)
        .replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
        .replace("'", "&#x27;")
    )
