"""
SVM Playground — interactive parameter exploration.
"""

import numpy as np

META = {
    "title": "Support Vector Machine",
    "icon": "⚔️",
    "description": (
        "Explore how SVM finds the optimal separating hyperplane. "
        "Adjust the regularization parameter C and kernel type to see "
        "how the decision boundary transforms."
    ),
}

PARAMS = [
    {
        "name": "C",
        "label": "C (Regularization)",
        "type": "slider",
        "min": 0.01,
        "max": 100.0,
        "step": 0.5,
        "default": 1.0,
    },
    {
        "name": "kernel",
        "label": "Kernel",
        "type": "select",
        "options": ["linear", "rbf", "poly"],
        "default": "rbf",
    },
    {
        "name": "noise",
        "label": "Noise / Spread",
        "type": "slider",
        "min": 0.3,
        "max": 2.0,
        "step": 0.1,
        "default": 0.8,
    },
    {
        "name": "n_points",
        "label": "Points per Class",
        "type": "slider",
        "min": 30,
        "max": 150,
        "step": 10,
        "default": 60,
    },
]


def compute(params: dict) -> dict:
    """Fit SVM and show decision boundary with support vectors."""
    C = float(params.get("C", 1.0))
    kernel = params.get("kernel", "rbf")
    noise = float(params.get("noise", 0.8))
    n = int(params.get("n_points", 60))

    np.random.seed(42)
    c0 = np.random.randn(n, 2) * noise + [1, 1]
    c1 = np.random.randn(n, 2) * noise + [3, 3]
    X = np.vstack([c0, c1])
    y = np.array([0] * n + [1] * n)

    from sklearn.svm import SVC
    clf = SVC(C=C, kernel=kernel, gamma="scale")
    clf.fit(X, y)

    margin = 1.5
    x_min, x_max = X[:, 0].min() - margin, X[:, 0].max() + margin
    y_min, y_max = X[:, 1].min() - margin, X[:, 1].max() + margin
    res = 100
    xx, yy = np.meshgrid(np.linspace(x_min, x_max, res),
                          np.linspace(y_min, y_max, res))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape).astype(float)

    sv = clf.support_vectors_
    accuracy = clf.score(X, y)

    data = [
        {
            "z": Z.tolist(),
            "x": np.linspace(x_min, x_max, res).tolist(),
            "y": np.linspace(y_min, y_max, res).tolist(),
            "type": "heatmap",
            "colorscale": [[0, "rgba(108,99,255,0.25)"], [1, "rgba(255,101,132,0.25)"]],
            "showscale": False,
            "hoverinfo": "skip",
        },
        {
            "x": c0[:, 0].tolist(),
            "y": c0[:, 1].tolist(),
            "mode": "markers",
            "type": "scatter",
            "name": "Class 0",
            "marker": {"size": 7, "color": "#6C63FF", "opacity": 0.8,
                        "line": {"width": 1, "color": "#fff"}},
        },
        {
            "x": c1[:, 0].tolist(),
            "y": c1[:, 1].tolist(),
            "mode": "markers",
            "type": "scatter",
            "name": "Class 1",
            "marker": {"size": 7, "color": "#FF6584", "opacity": 0.8,
                        "line": {"width": 1, "color": "#fff"}},
        },
        {
            "x": sv[:, 0].tolist(),
            "y": sv[:, 1].tolist(),
            "mode": "markers",
            "type": "scatter",
            "name": f"Support Vectors ({len(sv)})",
            "marker": {"size": 14, "color": "rgba(0,0,0,0)", "symbol": "circle-open",
                        "line": {"width": 2.5, "color": "#fbbf24"}},
        },
    ]

    layout = {
        "template": "plotly_dark",
        "paper_bgcolor": "rgba(0,0,0,0)",
        "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": f"SVM — {kernel} kernel, C={C}, acc={accuracy:.1%}", "font": {"size": 20}},
        "xaxis": {"title": "Feature 1", "gridcolor": "rgba(255,255,255,0.08)"},
        "yaxis": {"title": "Feature 2", "gridcolor": "rgba(255,255,255,0.08)", "scaleanchor": "x"},
        "legend": {"x": 0.02, "y": 0.98},
        "margin": {"l": 60, "r": 30, "t": 60, "b": 50},
    }

    return {"data": data, "layout": layout}
