"""
Naive Bayes — comprehensive topic content with interactive graphs.
"""

import json
import numpy as np


def _gaussian_distributions():
    """Show Gaussian distributions for each class/feature."""
    x = np.linspace(-5, 10, 300)
    # Class 0: mean=2, std=1.5 | Class 1: mean=6, std=1.2
    y0 = (1 / (1.5 * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x - 2) / 1.5) ** 2)
    y1 = (1 / (1.2 * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x - 6) / 1.2) ** 2)

    data = [
        {"x": x.tolist(), "y": y0.tolist(), "mode": "lines", "type": "scatter", "name": "P(x | Class 0)",
         "line": {"color": "#6C63FF", "width": 3}, "fill": "tozeroy", "fillcolor": "rgba(108,99,255,0.15)"},
        {"x": x.tolist(), "y": y1.tolist(), "mode": "lines", "type": "scatter", "name": "P(x | Class 1)",
         "line": {"color": "#FF6584", "width": 3}, "fill": "tozeroy", "fillcolor": "rgba(255,101,132,0.15)"},
        {"x": [4.1, 4.1], "y": [0, 0.35], "mode": "lines", "type": "scatter", "name": "Decision Boundary",
         "line": {"color": "#fbbf24", "width": 2, "dash": "dash"}},
    ]
    layout = {
        "template": "plotly_dark", "paper_bgcolor": "rgba(0,0,0,0)", "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": "Gaussian Naive Bayes — Class Distributions", "font": {"size": 18}},
        "xaxis": {"title": "Feature Value", "gridcolor": "rgba(255,255,255,0.08)"},
        "yaxis": {"title": "Probability Density", "gridcolor": "rgba(255,255,255,0.08)"},
        "margin": {"l": 60, "r": 30, "t": 50, "b": 50},
    }
    return json.dumps({"data": data, "layout": layout})


def _prior_posterior():
    """Show prior vs posterior probabilities."""
    categories = ["Spam", "Not Spam"]
    priors = [0.3, 0.7]
    posteriors = [0.85, 0.15]

    data = [
        {"x": categories, "y": priors, "name": "Prior P(C)", "type": "bar",
         "marker": {"color": "#6C63FF", "line": {"width": 1.5, "color": "#fff"}}},
        {"x": categories, "y": posteriors, "name": "Posterior P(C|x)", "type": "bar",
         "marker": {"color": "#FF6584", "line": {"width": 1.5, "color": "#fff"}}},
    ]
    layout = {
        "template": "plotly_dark", "paper_bgcolor": "rgba(0,0,0,0)", "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": "Prior vs Posterior Probability", "font": {"size": 18}},
        "yaxis": {"title": "Probability", "gridcolor": "rgba(255,255,255,0.08)", "range": [0, 1]},
        "barmode": "group",
        "margin": {"l": 60, "r": 30, "t": 50, "b": 50},
    }
    return json.dumps({"data": data, "layout": layout})


def _spam_example():
    """Show word probabilities for spam detection."""
    words = ["free", "win", "money", "meeting", "project", "hello", "urgent", "click"]
    p_spam = [0.82, 0.76, 0.71, 0.08, 0.05, 0.15, 0.68, 0.73]
    p_ham = [0.12, 0.08, 0.10, 0.55, 0.62, 0.70, 0.15, 0.11]

    data = [
        {"y": words[::-1], "x": p_spam[::-1], "name": "P(word|Spam)", "type": "bar", "orientation": "h",
         "marker": {"color": "#FF6584"}},
        {"y": words[::-1], "x": p_ham[::-1], "name": "P(word|Ham)", "type": "bar", "orientation": "h",
         "marker": {"color": "#34d399"}},
    ]
    layout = {
        "template": "plotly_dark", "paper_bgcolor": "rgba(0,0,0,0)", "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": "Word Likelihoods for Spam Detection", "font": {"size": 18}},
        "xaxis": {"title": "P(word | class)", "gridcolor": "rgba(255,255,255,0.08)"},
        "barmode": "group",
        "margin": {"l": 80, "r": 30, "t": 50, "b": 50},
    }
    return json.dumps({"data": data, "layout": layout})


def get_content() -> dict:
    return {
        "title": "Naive Bayes",
        "icon": "📬",
        "subtitle": "Probabilistic classification using Bayes' theorem",
        "sections": [
            {"id": "introduction", "heading": "What is Naive Bayes?", "type": "text",
             "content": ("Naive Bayes is a family of <strong>probabilistic classifiers</strong> based on Bayes' theorem "
                         "with the '<strong>naive</strong>' assumption that all features are <strong>conditionally independent</strong> "
                         "given the class label.\n\nDespite this simplifying assumption, Naive Bayes works surprisingly well for "
                         "text classification, spam filtering, and sentiment analysis.")},
            {"id": "distributions", "heading": "Gaussian Naive Bayes", "type": "graph",
             "description": "For continuous features, Naive Bayes models each class's features as Gaussian distributions. The decision boundary is where the posterior probabilities are equal.",
             "graph_json": _gaussian_distributions()},
            {"id": "math", "heading": "The Mathematics", "type": "math",
             "content": [
                 {"label": "Bayes' Theorem", "formula": "P(C|X) = \\frac{P(X|C) \\cdot P(C)}{P(X)}",
                  "explanation": "Posterior = (Likelihood × Prior) / Evidence. We classify by finding the class with highest posterior."},
                 {"label": "Naive Independence Assumption", "formula": "P(x_1, x_2, ..., x_n | C) = \\prod_{i=1}^{n} P(x_i | C)",
                  "explanation": "Features are assumed independent given the class. This simplification makes computation tractable."},
                 {"label": "Classification Rule", "formula": "\\hat{y} = \\arg\\max_c \\, P(C=c) \\prod_{i=1}^{n} P(x_i | C=c)",
                  "explanation": "Pick the class that maximizes the product of prior and all feature likelihoods."},
             ]},
            {"id": "prior-posterior", "heading": "Prior vs Posterior", "type": "graph",
             "description": "The prior is our initial belief (e.g., 30% of emails are spam). After observing features like 'free' and 'click', the posterior updates dramatically.",
             "graph_json": _prior_posterior()},
            {"id": "spam", "heading": "Example: Spam Detection", "type": "graph",
             "description": "Each word has a different probability of appearing in spam vs legitimate email (ham). Words like 'free' and 'click' are strong spam indicators.",
             "graph_json": _spam_example()},
            {"id": "variants", "heading": "Naive Bayes Variants", "type": "list",
             "entries": [
                 {"title": "Gaussian NB", "detail": "Assumes continuous features follow a Gaussian distribution. Best for numeric data."},
                 {"title": "Multinomial NB", "detail": "Works with word counts / frequencies. The go-to for text classification and NLP."},
                 {"title": "Bernoulli NB", "detail": "Works with binary features (word present / absent). Good for short text and binary data."},
                 {"title": "Complement NB", "detail": "Modified Multinomial NB designed for imbalanced datasets. Often outperforms standard MNB."},
             ]},
            {"id": "implementation", "heading": "Python Implementation", "type": "code", "language": "python",
             "content": ("from sklearn.naive_bayes import GaussianNB, MultinomialNB\n"
                         "from sklearn.model_selection import train_test_split\n"
                         "from sklearn.datasets import load_iris\nfrom sklearn.metrics import accuracy_score\n\n"
                         "# Gaussian NB for continuous features\niris = load_iris()\nX, y = iris.data, iris.target\n"
                         "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n\n"
                         "model = GaussianNB()\nmodel.fit(X_train, y_train)\n"
                         "print(f'Accuracy: {accuracy_score(y_test, model.predict(X_test)):.4f}')\n\n"
                         "# For text classification, use MultinomialNB:\n"
                         "# from sklearn.feature_extraction.text import CountVectorizer\n"
                         "# vectorizer = CountVectorizer()\n"
                         "# X_counts = vectorizer.fit_transform(documents)\n"
                         "# model = MultinomialNB()\n"
                         "# model.fit(X_counts, labels)\n")},
            {"id": "tips", "heading": "Key Takeaways", "type": "list",
             "entries": [
                 {"title": "Blazing Fast", "detail": "Training is O(n×d) — just counting. One of the fastest classifiers to train and predict."},
                 {"title": "Great Baseline", "detail": "Always try Naive Bayes first for text/NLP tasks. It's simple, fast, and often surprisingly competitive."},
                 {"title": "Zero-Frequency Problem", "detail": "If a feature-class combination never appears in training, probability = 0. Use Laplace smoothing (alpha=1) to fix."},
                 {"title": "Independence is Rarely True", "detail": "Features are almost never truly independent, yet NB still works well. It's optimizing for the right class ranking, not calibrated probabilities."},
             ]},
        ],
    }
