
import os
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.metrics import (
    accuracy_score, precision_score, recall_score, f1_score,
    roc_auc_score, roc_curve, confusion_matrix,
)

FIGURES_DIR = "results/figures"
TABLES_DIR  = "results/tables"
os.makedirs(FIGURES_DIR, exist_ok=True)
os.makedirs(TABLES_DIR,  exist_ok=True)

PALETTE = {
    "Logistic Regression": "#4878CF",
    "Random Forest":       "#6ACC65",
    "SVM":                 "#D65F5F",
    "Gradient Boosting":   "#B47CC7",
    "ANN (MLP)":           "#C4AD66",
}


# METRICS

def evaluate_all_models(fitted_models, X_test, y_test, disease):
    rows = []
    for name, model in fitted_models.items():
        y_pred  = model.predict(X_test)
        y_proba = model.predict_proba(X_test)[:, 1]
        rows.append({
            "Model":     name,
            "Accuracy":  round(accuracy_score(y_test, y_pred), 4),
            "Precision": round(precision_score(y_test, y_pred, zero_division=0), 4),
            "Recall":    round(recall_score(y_test, y_pred, zero_division=0), 4),
            "F1":        round(f1_score(y_test, y_pred, zero_division=0), 4),
            "AUC-ROC":   round(roc_auc_score(y_test, y_proba), 4),
        })
        print(f"    {name:22s} | Acc={rows[-1]['Accuracy']:.4f} "
              f"| P={rows[-1]['Precision']:.4f} | R={rows[-1]['Recall']:.4f} "
              f"| F1={rows[-1]['F1']:.4f} | AUC={rows[-1]['AUC-ROC']:.4f}")

    df = pd.DataFrame(rows).set_index("Model")
    df.to_csv(os.path.join(TABLES_DIR, f"{disease}_results.csv"))
    return df


# PLOTS

def plot_roc(fitted_models, X_test, y_test, disease):
    fig, ax = plt.subplots(figsize=(8, 6))
    for name, model in fitted_models.items():
        y_proba = model.predict_proba(X_test)[:, 1]
        fpr, tpr, _ = roc_curve(y_test, y_proba)
        auc = roc_auc_score(y_test, y_proba)
        ax.plot(fpr, tpr, label=f"{name} (AUC={auc:.3f})",
                color=PALETTE.get(name, "#999"), linewidth=2)
    ax.plot([0, 1], [0, 1], "k--", lw=1)
    ax.set_xlabel("False Positive Rate", fontsize=12)
    ax.set_ylabel("True Positive Rate", fontsize=12)
    ax.set_title(f"ROC Curves — {disease}", fontsize=14, fontweight="bold")
    ax.legend(loc="lower right", fontsize=9)
    ax.grid(True, alpha=0.3)
    plt.tight_layout()
    path = os.path.join(FIGURES_DIR, f"{disease}_roc.png")
    fig.savefig(path, dpi=150)
    plt.close(fig)
    print(f"  [Saved] {path}")


def plot_metrics_bar(results_df, disease):
    metrics  = ["Accuracy", "Precision", "Recall", "F1", "AUC-ROC"]
    df_melt  = (results_df[metrics].reset_index()
                .melt(id_vars="Model", var_name="Metric", value_name="Score"))
    palette  = [PALETTE.get(m, "#888") for m in results_df.index]

    fig, ax = plt.subplots(figsize=(12, 6))
    sns.barplot(data=df_melt, x="Metric", y="Score", hue="Model",
                palette=palette, ax=ax)
    ax.set_ylim(0, 1.05)
    ax.set_title(f"Model Performance — {disease}", fontsize=14, fontweight="bold")
    ax.set_ylabel("Score", fontsize=12)
    ax.set_xlabel("")
    ax.legend(bbox_to_anchor=(1.01, 1), loc="upper left", fontsize=9)
    ax.grid(True, axis="y", alpha=0.3)
    plt.tight_layout()
    path = os.path.join(FIGURES_DIR, f"{disease}_metrics_bar.png")
    fig.savefig(path, dpi=150)
    plt.close(fig)
    print(f"  [Saved] {path}")


def plot_confusion_matrices(fitted_models, X_test, y_test, disease):
    n = len(fitted_models)
    cols = min(3, n)
    rows = (n + cols - 1) // cols
    fig, axes = plt.subplots(rows, cols, figsize=(cols * 4.5, rows * 4))
    axes = np.array(axes).flatten()
    for i, (name, model) in enumerate(fitted_models.items()):
        cm = confusion_matrix(y_test, model.predict(X_test))
        sns.heatmap(cm, annot=True, fmt="d", cmap="Blues",
                    ax=axes[i], cbar=False, linewidths=0.5)
        axes[i].set_title(name, fontsize=11, fontweight="bold")
        axes[i].set_xlabel("Predicted"); axes[i].set_ylabel("Actual")
    for j in range(i + 1, len(axes)):
        axes[j].set_visible(False)
    fig.suptitle(f"Confusion Matrices — {disease}", fontsize=14,
                 fontweight="bold", y=1.01)
    plt.tight_layout()
    path = os.path.join(FIGURES_DIR, f"{disease}_confusion.png")
    fig.savefig(path, dpi=150, bbox_inches="tight")
    plt.close(fig)
    print(f"  [Saved] {path}")


def plot_feature_importance(model, feats, disease, model_name, top_n=15):
    if not hasattr(model, "feature_importances_"):
        print(f"  [Skip] {model_name} has no feature_importances_")
        return
    imp = model.feature_importances_
    idx = np.argsort(imp)[::-1][:top_n]
    fig, ax = plt.subplots(figsize=(9, 6))
    ax.barh(range(len(idx)), imp[idx][::-1], color="#4878CF", edgecolor="white")
    ax.set_yticks(range(len(idx)))
    ax.set_yticklabels([feats[i] for i in idx][::-1], fontsize=10)
    ax.set_xlabel("Importance", fontsize=12)
    ax.set_title(f"Top {len(idx)} Features ({model_name}) — {disease}",
                 fontsize=13, fontweight="bold")
    ax.grid(True, axis="x", alpha=0.3)
    plt.tight_layout()
    path = os.path.join(FIGURES_DIR, f"{disease}_feature_importance.png")
    fig.savefig(path, dpi=150)
    plt.close(fig)
    print(f"  [Saved] {path}")


# CROSS-DISEASE COMPARISON

def plot_cross_disease_heatmap(all_results):
    summary = pd.DataFrame({d: r["AUC-ROC"] for d, r in all_results.items()})
    fig, ax = plt.subplots(figsize=(8, 5))
    sns.heatmap(summary, annot=True, fmt=".3f", cmap="YlOrRd",
                vmin=0.5, vmax=1.0, linewidths=0.5,
                cbar_kws={"label": "AUC-ROC"}, ax=ax)
    ax.set_title("AUC-ROC: All Models × All Diseases",
                 fontsize=13, fontweight="bold")
    ax.set_xlabel("Disease", fontsize=11)
    ax.set_ylabel("Model", fontsize=11)
    plt.tight_layout()
    path = os.path.join(FIGURES_DIR, "cross_disease_auc_heatmap.png")
    fig.savefig(path, dpi=150)
    plt.close(fig)
    print(f"  [Saved] {path}")
    summary.to_csv(os.path.join(TABLES_DIR, "cross_disease_summary.csv"))
    return summary


def plot_cross_disease_bar(all_results):
    rows = []
    for disease, df in all_results.items():
        for model_name, row in df.iterrows():
            rows.append({"Disease": disease, "Model": model_name,
                         "AUC-ROC": row["AUC-ROC"]})
    combined = pd.DataFrame(rows)
    diseases = list(all_results.keys())
    models   = combined["Model"].unique()
    x        = np.arange(len(diseases))
    width    = 0.15
    offsets  = np.linspace(-(len(models)-1)*width/2,
                            (len(models)-1)*width/2, len(models))
    fig, ax  = plt.subplots(figsize=(13, 6))
    for i, model in enumerate(models):
        vals = [combined[(combined["Disease"] == d) &
                         (combined["Model"] == model)]["AUC-ROC"].values
                for d in diseases]
        vals = [v[0] if len(v) > 0 else 0 for v in vals]
        ax.bar(x + offsets[i], vals, width, label=model,
               color=PALETTE.get(model, "#888"), edgecolor="white")
    ax.set_xticks(x)
    ax.set_xticklabels(diseases, fontsize=12)
    ax.set_ylim(0.5, 1.05)
    ax.set_ylabel("AUC-ROC", fontsize=12)
    ax.set_title("AUC-ROC Across All Diseases and Models",
                 fontsize=14, fontweight="bold")
    ax.legend(bbox_to_anchor=(1.01, 1), loc="upper left", fontsize=9)
    ax.grid(True, axis="y", alpha=0.3)
    plt.tight_layout()
    path = os.path.join(FIGURES_DIR, "cross_disease_auc_bar.png")
    fig.savefig(path, dpi=150)
    plt.close(fig)
    print(f"  [Saved] {path}")
