"""
Neural Networks — comprehensive topic content with interactive graphs.
"""

import json
import numpy as np


def _network_architecture():
    """Visualize a simple neural network as a node-link diagram using scatter + lines."""
    layers = [3, 5, 4, 2]  # input, hidden1, hidden2, output
    layer_names = ["Input\nLayer", "Hidden\nLayer 1", "Hidden\nLayer 2", "Output\nLayer"]
    node_x, node_y, node_colors, node_text = [], [], [], []
    edge_x, edge_y = [], []

    for l, n_nodes in enumerate(layers):
        for n in range(n_nodes):
            y_pos = (n - (n_nodes - 1) / 2) * 1.2
            node_x.append(l * 3)
            node_y.append(y_pos)
            node_colors.append(["#6C63FF", "#a78bfa", "#a78bfa", "#FF6584"][l])
            node_text.append(f"Layer {l+1}, Neuron {n+1}")

    # Draw edges
    idx = 0
    for l in range(len(layers) - 1):
        n1 = layers[l]
        n2 = layers[l + 1]
        for i in range(n1):
            for j in range(n2):
                x1 = l * 3
                y1 = (i - (n1 - 1) / 2) * 1.2
                x2 = (l + 1) * 3
                y2 = (j - (n2 - 1) / 2) * 1.2
                edge_x.extend([x1, x2, None])
                edge_y.extend([y1, y2, None])

    data = [
        {"x": edge_x, "y": edge_y, "mode": "lines", "type": "scatter",
         "line": {"color": "rgba(167,139,250,0.2)", "width": 1}, "hoverinfo": "none", "showlegend": False},
        {"x": node_x, "y": node_y, "mode": "markers+text", "type": "scatter",
         "marker": {"size": 28, "color": node_colors, "line": {"width": 2, "color": "#fff"}},
         "text": ["" for _ in node_x], "hovertext": node_text, "hoverinfo": "text", "showlegend": False},
    ]
    # Add layer labels
    for l, name in enumerate(layer_names):
        data.append({"x": [l * 3], "y": [-(max(layers) / 2) * 1.2 - 0.8], "mode": "text", "type": "scatter",
                     "text": [name], "textfont": {"size": 12, "color": "#a0a0b8"}, "showlegend": False})

    layout = {
        "template": "plotly_dark", "paper_bgcolor": "rgba(0,0,0,0)", "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": "Neural Network Architecture (3→5→4→2)", "font": {"size": 18}},
        "xaxis": {"showgrid": False, "zeroline": False, "showticklabels": False},
        "yaxis": {"showgrid": False, "zeroline": False, "showticklabels": False, "scaleanchor": "x"},
        "margin": {"l": 20, "r": 20, "t": 50, "b": 60},
    }
    return json.dumps({"data": data, "layout": layout})


def _forward_pass():
    """Show a single neuron's computation."""
    inputs = ["x₁ = 0.5", "x₂ = 0.3", "x₃ = 0.8"]
    weights = [0.4, -0.2, 0.6]
    bias = 0.1
    z = sum(i * w for i, w in zip([0.5, 0.3, 0.8], weights)) + bias
    a = 1 / (1 + np.exp(-z))

    steps = ["Weighted Sum (z)", "After ReLU", "After Sigmoid"]
    values = [z, max(0, z), a]
    colors = ["#6C63FF", "#34d399", "#FF6584"]

    data = [{"x": steps, "y": values, "type": "bar",
             "marker": {"color": colors, "line": {"width": 1.5, "color": "#fff"}},
             "text": [f"{v:.3f}" for v in values], "textposition": "outside",
             "textfont": {"color": "#e0e0e0", "size": 14}}]
    layout = {
        "template": "plotly_dark", "paper_bgcolor": "rgba(0,0,0,0)", "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": "Single Neuron Computation (x=[0.5, 0.3, 0.8])", "font": {"size": 18}},
        "yaxis": {"title": "Output Value", "gridcolor": "rgba(255,255,255,0.08)"},
        "margin": {"l": 60, "r": 30, "t": 50, "b": 50},
    }
    return json.dumps({"data": data, "layout": layout})


def _training_loss():
    """Show training loss decreasing over epochs."""
    np.random.seed(42)
    epochs = list(range(1, 101))
    loss = [2.5 * np.exp(-0.05 * e) + 0.1 + np.random.normal(0, 0.03) for e in epochs]
    val_loss = [2.5 * np.exp(-0.04 * e) + 0.2 + np.random.normal(0, 0.04) for e in epochs]

    data = [
        {"x": epochs, "y": loss, "mode": "lines", "type": "scatter", "name": "Training Loss",
         "line": {"color": "#6C63FF", "width": 2.5}},
        {"x": epochs, "y": val_loss, "mode": "lines", "type": "scatter", "name": "Validation Loss",
         "line": {"color": "#FF6584", "width": 2.5}},
    ]
    layout = {
        "template": "plotly_dark", "paper_bgcolor": "rgba(0,0,0,0)", "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": "Training Progress Over Epochs", "font": {"size": 18}},
        "xaxis": {"title": "Epoch", "gridcolor": "rgba(255,255,255,0.08)"},
        "yaxis": {"title": "Loss", "gridcolor": "rgba(255,255,255,0.08)"},
        "margin": {"l": 60, "r": 30, "t": 50, "b": 50},
    }
    return json.dumps({"data": data, "layout": layout})


def get_content() -> dict:
    return {
        "title": "Neural Networks",
        "icon": "🧠",
        "subtitle": "The foundation of deep learning",
        "sections": [
            {"id": "introduction", "heading": "What are Neural Networks?", "type": "text",
             "content": ("A Neural Network is a computational model inspired by the biological brain. It consists of "
                         "layers of interconnected <strong>neurons</strong> (nodes) that learn to map inputs to outputs "
                         "by adjusting <strong>weights</strong> during training.\n\n"
                         "Neural networks can learn complex, non-linear patterns that simpler models cannot capture, "
                         "making them the backbone of modern AI.")},
            {"id": "architecture", "heading": "Network Architecture", "type": "graph",
             "description": "A typical feedforward neural network. Data flows left to right: input features → hidden layers (where computation happens) → output predictions. Each connection has a learnable weight.",
             "graph_json": _network_architecture()},
            {"id": "neuron", "heading": "Inside a Single Neuron", "type": "graph",
             "description": "Each neuron computes: z = Σ(wᵢ×xᵢ) + b, then passes z through an activation function. The bar chart shows 3 stages: raw weighted sum, after ReLU, and after Sigmoid.",
             "graph_json": _forward_pass()},
            {"id": "math", "heading": "The Mathematics", "type": "math",
             "content": [
                 {"label": "Single Neuron", "formula": "a = \\sigma(w^T x + b)",
                  "explanation": "Output = activation function applied to the weighted sum of inputs plus bias."},
                 {"label": "Layer Computation", "formula": "A^{[l]} = \\sigma(W^{[l]} A^{[l-1]} + b^{[l]})",
                  "explanation": "Each layer applies weights, adds bias, and passes through an activation function. Matrix form allows batch processing."},
                 {"label": "Network Output (Classification)", "formula": "\\hat{y} = \\text{softmax}(W^{[L]} A^{[L-1]} + b^{[L]})",
                  "explanation": "The final layer uses softmax (multi-class) or sigmoid (binary) to produce class probabilities."},
                 {"label": "Loss Function", "formula": "\\mathcal{L} = -\\frac{1}{m} \\sum_{i=1}^{m} \\sum_{k=1}^{K} y_k^{(i)} \\log(\\hat{y}_k^{(i)})",
                  "explanation": "Cross-entropy loss measures how far predicted probabilities are from true labels."},
             ]},
            {"id": "training", "heading": "Training Progress", "type": "graph",
             "description": "During training, the loss decreases as the network learns. When validation loss starts rising while training loss keeps dropping, the network is overfitting.",
             "graph_json": _training_loss()},
            {"id": "components", "heading": "Key Components", "type": "list",
             "entries": [
                 {"title": "Weights & Biases", "detail": "Learnable parameters. Weights control connection strength; biases shift the activation. Initialized randomly."},
                 {"title": "Activation Functions", "detail": "ReLU (hidden layers), Sigmoid (binary output), Softmax (multi-class), Tanh. They introduce non-linearity."},
                 {"title": "Forward Pass", "detail": "Data flows from input → output through the network. Each layer transforms the data step by step."},
                 {"title": "Loss Function", "detail": "Measures prediction error. Cross-entropy for classification, MSE for regression."},
                 {"title": "Backpropagation", "detail": "Computes gradients of loss w.r.t. each weight using the chain rule. The heart of training."},
                 {"title": "Optimizer", "detail": "Uses gradients to update weights. SGD, Adam, RMSProp. Controls how big each update step is."},
             ]},
            {"id": "implementation", "heading": "Python Implementation", "type": "code", "language": "python",
             "content": ("import torch\nimport torch.nn as nn\nimport torch.optim as optim\n\n"
                         "# Define a simple neural network\nclass SimpleNet(nn.Module):\n"
                         "    def __init__(self, input_size, hidden_size, num_classes):\n"
                         "        super().__init__()\n"
                         "        self.layer1 = nn.Linear(input_size, hidden_size)\n"
                         "        self.relu = nn.ReLU()\n"
                         "        self.layer2 = nn.Linear(hidden_size, hidden_size)\n"
                         "        self.layer3 = nn.Linear(hidden_size, num_classes)\n\n"
                         "    def forward(self, x):\n"
                         "        x = self.relu(self.layer1(x))\n"
                         "        x = self.relu(self.layer2(x))\n"
                         "        return self.layer3(x)\n\n"
                         "# Create model, loss, optimizer\n"
                         "model = SimpleNet(input_size=4, hidden_size=32, num_classes=3)\n"
                         "criterion = nn.CrossEntropyLoss()\n"
                         "optimizer = optim.Adam(model.parameters(), lr=0.001)\n\n"
                         "# Training loop (pseudocode)\n"
                         "for epoch in range(100):\n"
                         "    outputs = model(X_train)        # forward pass\n"
                         "    loss = criterion(outputs, y_train)  # compute loss\n"
                         "    optimizer.zero_grad()            # clear gradients\n"
                         "    loss.backward()                  # backpropagation\n"
                         "    optimizer.step()                 # update weights\n")},
            {"id": "tips", "heading": "Key Takeaways", "type": "list",
             "entries": [
                 {"title": "Universal Approximators", "detail": "A network with one hidden layer can theoretically approximate any continuous function. Depth helps learn hierarchical features."},
                 {"title": "More Data = Better", "detail": "Neural networks are data-hungry. They really shine with thousands to millions of examples."},
                 {"title": "Regularization is Critical", "detail": "Use Dropout, weight decay, early stopping, and data augmentation to prevent overfitting."},
                 {"title": "GPU Acceleration", "detail": "Training on GPU is 10-100x faster. Use CUDA with PyTorch or TensorFlow for any serious work."},
             ]},
        ],
    }
