"""
Decision Tree Playground — interactive parameter exploration.
"""

import numpy as np

META = {
    "title": "Decision Tree",
    "icon": "🌳",
    "description": (
        "See how a decision tree carves up feature space into rectangular regions. "
        "Increase max depth for tighter boundaries (risk of overfitting) or "
        "decrease it for simpler, more generalizable models."
    ),
}

PARAMS = [
    {
        "name": "max_depth",
        "label": "Max Depth",
        "type": "slider",
        "min": 1,
        "max": 12,
        "step": 1,
        "default": 3,
    },
    {
        "name": "n_points",
        "label": "Points per Class",
        "type": "slider",
        "min": 30,
        "max": 200,
        "step": 10,
        "default": 80,
    },
    {
        "name": "noise",
        "label": "Noise / Spread",
        "type": "slider",
        "min": 0.3,
        "max": 2.0,
        "step": 0.1,
        "default": 1.0,
    },
]


def compute(params: dict) -> dict:
    """Build a decision tree and show the decision boundary."""
    max_depth = int(params.get("max_depth", 3))
    n = int(params.get("n_points", 80))
    noise = float(params.get("noise", 1.0))

    np.random.seed(42)
    # Three clusters in a triangle
    c0 = np.random.randn(n, 2) * noise + [0, 2]
    c1 = np.random.randn(n, 2) * noise + [3, -1]
    c2 = np.random.randn(n, 2) * noise + [-3, -1]
    X = np.vstack([c0, c1, c2])
    y = np.array([0] * n + [1] * n + [2] * n)

    # Use sklearn decision tree
    from sklearn.tree import DecisionTreeClassifier
    clf = DecisionTreeClassifier(max_depth=max_depth, random_state=42)
    clf.fit(X, y)

    margin = 2
    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)

    accuracy = clf.score(X, y)

    colors = ["#6C63FF", "#FF6584", "#34d399"]
    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.2)"], [0.5, "rgba(255,101,132,0.2)"], [1, "rgba(52,211,153,0.2)"]],
            "showscale": False,
            "hoverinfo": "skip",
        },
    ]

    class_names = ["Class 0", "Class 1", "Class 2"]
    class_data = [c0, c1, c2]
    for i in range(3):
        data.append({
            "x": class_data[i][:, 0].tolist(),
            "y": class_data[i][:, 1].tolist(),
            "mode": "markers",
            "type": "scatter",
            "name": class_names[i],
            "marker": {"size": 7, "color": colors[i], "opacity": 0.8,
                        "line": {"width": 1, "color": "#fff"}},
        })

    layout = {
        "template": "plotly_dark",
        "paper_bgcolor": "rgba(0,0,0,0)",
        "plot_bgcolor": "rgba(0,0,0,0)",
        "title": {"text": f"Decision Tree (depth={max_depth}, 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}
