import warnings

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler

warnings.filterwarnings("ignore")

DATA_URL = "https://autotrain.app/opendata92bd.html?file=breast-cancer.csv"

df = pd.read_csv(DATA_URL)
possible_targets = ["diagnosis", "target", "class", "label"]
target_col = next((col for col in possible_targets if col in df.columns), df.columns[-1])

df_clean = df.copy()
for col in list(df_clean.columns):
    if "unnamed" in col.lower() or col.lower() == "id":
        df_clean = df_clean.drop(columns=[col])

X = df_clean.drop(columns=[target_col]).select_dtypes(include=["int64", "float64"])
y = df_clean[target_col]

target_encoder = LabelEncoder()
y_encoded = target_encoder.fit_transform(y.astype(str))

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y_encoded,
    test_size=0.2,
    random_state=42,
    stratify=y_encoded,
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

baseline_model = LogisticRegression(max_iter=1000, random_state=42)
baseline_model.fit(X_train_scaled, y_train)
baseline_preds = baseline_model.predict(X_test_scaled)

baseline_scores = {
    "model": "Baseline Logistic Regression",
    "accuracy": accuracy_score(y_test, baseline_preds),
    "precision": precision_score(y_test, baseline_preds, zero_division=0),
    "recall": recall_score(y_test, baseline_preds, zero_division=0),
    "f1": f1_score(y_test, baseline_preds, zero_division=0),
}

pca = PCA(n_components=2, random_state=42)
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = pca.transform(X_test_scaled)

pca_model = LogisticRegression(max_iter=1000, random_state=42)
pca_model.fit(X_train_pca, y_train)
pca_preds = pca_model.predict(X_test_pca)
pca_scores = {
    "model": "Logistic Regression + PCA",
    "accuracy": accuracy_score(y_test, pca_preds),
    "precision": precision_score(y_test, pca_preds, zero_division=0),
    "recall": recall_score(y_test, pca_preds, zero_division=0),
    "f1": f1_score(y_test, pca_preds, zero_division=0),
}

lda = LinearDiscriminantAnalysis(n_components=1)
X_train_lda = lda.fit_transform(X_train_scaled, y_train)
X_test_lda = lda.transform(X_test_scaled)

lda_model = LogisticRegression(max_iter=1000, random_state=42)
lda_model.fit(X_train_lda, y_train)
lda_preds = lda_model.predict(X_test_lda)
lda_scores = {
    "model": "Logistic Regression + LDA",
    "accuracy": accuracy_score(y_test, lda_preds),
    "precision": precision_score(y_test, lda_preds, zero_division=0),
    "recall": recall_score(y_test, lda_preds, zero_division=0),
    "f1": f1_score(y_test, lda_preds, zero_division=0),
}

comparison_df = pd.DataFrame([baseline_scores, pca_scores, lda_scores]).sort_values(
    "f1", ascending=False
)
print(comparison_df)

plt.figure(figsize=(8, 6))
plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1], c=y_train, alpha=0.7)
plt.title("PCA Projection - Training Data")
plt.xlabel("Principal Component 1")
plt.ylabel("Principal Component 2")
plt.tight_layout()
plt.show()

plt.figure(figsize=(8, 4))
for class_id in np.unique(y_train):
    plt.hist(
        X_train_lda[y_train == class_id, 0],
        bins=20,
        alpha=0.6,
        label=str(target_encoder.inverse_transform([class_id])[0]),
    )
plt.title("LDA Projection - Training Data")
plt.xlabel("Linear Discriminant 1")
plt.ylabel("Frequency")
plt.legend()
plt.tight_layout()
plt.show()

