# Advanced demo: Handle errors in API calls, multiple files, preprocess, model with LinearRegression, evaluate, visualize
import requests
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import json

class APIError(Exception):
    pass

def advanced_error_api_demo():
    # Call API with error handling
    try:
        response = requests.get("https://jsonplaceholder.typicode.com/users", timeout=5)
        response.raise_for_status()
        users = response.json()
    except requests.exceptions.HTTPError as e:
        print(f"HTTP Error: {e}")
        raise APIError("API call failed due to HTTP error")
    except requests.exceptions.Timeout:
        print("Request timed out")
        raise APIError("API request timed out")
    except Exception as e:
        print(f"Error fetching API: {e}")
        raise APIError("Unexpected API error")
    # Preprocess and write with error handling
    try:
        users_df = pd.DataFrame(users)[['id', 'name', 'username']]
        users_df['Feature_Engineered'] = users_df['name'].apply(len) / (users_df['username'].apply(len) + 1e-5)
        users_df.to_csv('users_data.csv', index=False)
        users_df.to_json('users_data.json', orient='records')
    except Exception as e:
        print(f"Error writing files: {e}")
        raise ValueError("File write failed")
    # Read multiple files with error handling
    try:
        df_csv = pd.read_csv('users_data.csv')
    except FileNotFoundError:
        print("CSV file not found")
        raise FileNotFoundError("Missing users_data.csv")
    try:
        with open('users_data.json', 'r') as f:
            df_json = pd.DataFrame(json.load(f))
    except FileNotFoundError:
        print("JSON file not found")
        raise FileNotFoundError("Missing users_data.json")
    try:
        df_merged = pd.merge(df_csv, df_json, on=['id', 'name', 'username', 'Feature_Engineered'], how='inner')
    except Exception as e:
        print(f"Error merging data: {e}")
        raise ValueError("Data merge failed")
    # Model and evaluate
    try:
        df_merged['Synthetic_Target'] = np.random.rand(len(df_merged)) * 100
        X = df_merged.drop('Synthetic_Target', axis=1).select_dtypes(include=np.number)
        y = df_merged['Synthetic_Target']
        scaler = StandardScaler()
        X_scaled = scaler.fit_transform(X)
        X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
        model = LinearRegression()
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
        mse = mean_squared_error(y_test, y_pred)
        r2 = r2_score(y_test, y_pred)
        print(f"MSE: {mse:.2f}, R2: {r2:.2f}")
        # Visualize
        plt.scatter(y_test, y_pred, c='blue', alpha=0.5)
        plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2)
        plt.title('API Error Handling Regression Predictions')
        plt.xlabel('True Values')
        plt.ylabel('Predictions')
        plt.annotate('Best Fit', xy=(y_test.mean(), y_pred.mean()), xytext=(y_test.mean() + 0.5, y_pred.mean() + 0.5), arrowprops=dict(facecolor='black', shrink=0.05))
        plt.show()
    except Exception as e:
        print(f"Error in modeling/visualization: {e}")
        raise ValueError("Modeling or visualization failed")

advanced_error_api_demo()