"""
ConvMLP Quick Start Guide
=========================
"""

import numpy as np
from sklearn.datasets import make_classification, load_digits
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

from convmlp import ConvMLPClassifier


# ============================================================================
# EXAMPLE 1: Simple 2D Classification
# ============================================================================

def example_simple():
    print("=" * 60)
    print("Example 1: Simple 2D Classification")
    print("=" * 60)
    
    # Generate synthetic data (images will be auto-detected as 8x8)
    X, y = make_classification(
        n_samples=1000, n_features=64, n_classes=3,
        n_informative=32, random_state=42
    )
    
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )
    
    # Create model with input shape hint
    model = ConvMLPClassifier(
        conv_layers=[
            {'type': 'conv2d', 'filters': 16, 'kernel_size': 3, 'padding': 'same', 'activation': 'relu'},
            {'type': 'maxpool2d', 'pool_size': 2},
            {'type': 'conv2d', 'filters': 32, 'kernel_size': 3, 'padding': 'same', 'activation': 'relu'},
            {'type': 'maxpool2d', 'pool_size': 2},
            {'type': 'flatten'},
        ],
        mlp_layers=[64, 32],
        conv_method='im2col',
        max_iter=50,
        random_state=42,
        verbose=True,
        input_shape=(1, 8, 8)  # 8x8 grayscale images
    )
    
    model.fit(X_train, y_train)
    
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    
    print(f"\nAccuracy: {accuracy:.4f}")
    print(classification_report(y_test, y_pred))


# ============================================================================
# EXAMPLE 2: MNIST-like Digits
# ============================================================================

def example_digits():
    print("\n" + "=" * 60)
    print("Example 2: MNIST-like Digits Classification")
    print("=" * 60)
    
    digits = load_digits()
    X, y = digits.data, digits.target
    
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )
    
    model = ConvMLPClassifier(
        conv_layers=[
            {'type': 'conv2d', 'filters': 32, 'kernel_size': 3, 'padding': 'same', 'activation': 'relu'},
            {'type': 'batchnorm'},
            {'type': 'maxpool2d', 'pool_size': 2},
            {'type': 'conv2d', 'filters': 64, 'kernel_size': 3, 'padding': 'same', 'activation': 'relu'},
            {'type': 'batchnorm'},
            {'type': 'maxpool2d', 'pool_size': 2},
            {'type': 'flatten'},
        ],
        mlp_layers=[128, 64],
        conv_method='im2col',
        max_iter=100,
        batch_size=64,
        random_state=42,
        verbose=True,
        input_shape=(1, 8, 8)
    )
    
    model.fit(X_train, y_train)
    
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    
    print(f"\nAccuracy: {accuracy:.4f}")
    print(classification_report(y_test, y_pred))


# ============================================================================
# EXAMPLE 3: Custom Architecture with FFT Method
# ============================================================================

def example_fft_method():
    print("\n" + "=" * 60)
    print("Example 3: FFT Convolution Method (Large Kernels)")
    print("=" * 60)
    
    # Generate larger images
    X = np.random.randn(500, 144).astype(np.float32)  # 12x12 images
    y = np.random.randint(0, 5, 500)
    
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )
    
    # FFT method is better for larger kernels
    model = ConvMLPClassifier(
        conv_layers=[
            {'type': 'conv2d', 'filters': 16, 'kernel_size': 5, 'padding': 'same', 'activation': 'relu'},
            {'type': 'maxpool2d', 'pool_size': 2},
            {'type': 'flatten'},
        ],
        mlp_layers=[32],
        conv_method='fft',  # FFT is faster for larger kernels
        max_iter=50,
        random_state=42,
        verbose=True,
        input_shape=(1, 12, 12)
    )
    
    model.fit(X_train, y_train)
    
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    
    print(f"\nAccuracy: {accuracy:.4f}")


# ============================================================================
# EXAMPLE 4: Regression with ConvMLPRegressor
# ============================================================================

def example_regression():
    print("\n" + "=" * 60)
    print("Example 4: Regression with ConvMLPRegressor")
    print("=" * 60)
    
    from convmlp import ConvMLPRegressor
    
    # Generate regression data
    X = np.random.randn(500, 64).astype(np.float32)
    y = np.sum(X[:, :10], axis=1) + 0.1 * np.random.randn(500)  # Simple linear + noise
    
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )
    
    model = ConvMLPRegressor(
        conv_layers=[
            {'type': 'conv2d', 'filters': 16, 'kernel_size': 3, 'padding': 'same', 'activation': 'relu'},
            {'type': 'flatten'},
        ],
        mlp_layers=[32],
        conv_method='im2col',
        max_iter=50,
        random_state=42,
        verbose=True,
        input_shape=(1, 8, 8)
    )
    
    model.fit(X_train, y_train)
    
    y_pred = model.predict(X_test)
    
    from sklearn.metrics import mean_squared_error, r2_score
    mse = mean_squared_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    
    print(f"\nMSE: {mse:.4f}")
    print(f"R²: {r2:.4f}")


# ============================================================================
# MAIN
# ============================================================================

if __name__ == "__main__":
    example_simple()
    example_digits()
    example_fft_method()
    example_regression()