#![allow(dead_code, unused)]
//! # Basic Query Examples
//!
//! This example demonstrates the fundamental query operations in Prax:
//! - Finding records (find_many, find_unique, find_first)
//! - Creating records
//! - Updating records
//! - Deleting records
//!
//! ## Running this example
//!
//! ```bash
//! # Set up your database URL
//! export DATABASE_URL="postgresql://localhost/prax_example"
//!
//! # Run the example
//! cargo run --example basic_queries
//! ```

// This would be generated by prax-codegen from your schema
mod generated {
    #![allow(dead_code)]

    /// User model representing a user in the system
    #[derive(Debug, Clone)]
    pub struct User {
        pub id: i32,
        pub email: String,
        pub name: Option<String>,
        pub active: bool,
        pub created_at: chrono::DateTime<chrono::Utc>,
    }

    /// Post model representing a blog post
    #[derive(Debug, Clone)]
    pub struct Post {
        pub id: i32,
        pub title: String,
        pub content: Option<String>,
        pub published: bool,
        pub author_id: i32,
    }

    // Mock filter types that would be generated
    pub mod user {

        pub mod id {
            pub fn equals(value: i32) -> String {
                format!("id = {}", value)
            }
        }

        pub mod email {
            pub fn equals(value: &str) -> String {
                format!("email = '{}'", value)
            }

            pub fn contains(value: &str) -> String {
                format!("email LIKE '%{}%'", value)
            }

            pub fn ends_with(value: &str) -> String {
                format!("email LIKE '%{}'", value)
            }
        }

        pub mod name {
            pub fn equals(value: &str) -> String {
                format!("name = '{}'", value)
            }

            pub fn starts_with(value: &str) -> String {
                format!("name LIKE '{}%'", value)
            }
        }

        pub mod active {
            pub fn equals(value: bool) -> String {
                format!("active = {}", value)
            }
        }

        pub mod created_at {
            pub fn desc() -> String {
                "created_at DESC".to_string()
            }

            pub fn asc() -> String {
                "created_at ASC".to_string()
            }
        }
    }
}

use generated::{User, user};

/// Mock client for demonstration purposes
/// In real usage, this would be generated from your schema
struct PraxClient {
    // Connection pool would go here
}

impl PraxClient {
    async fn new(_url: &str) -> Result<Self, Box<dyn std::error::Error>> {
        Ok(Self {})
    }

    fn user(&self) -> UserQueryBuilder {
        UserQueryBuilder::new()
    }

    fn post(&self) -> PostQueryBuilder {
        PostQueryBuilder::new()
    }
}

// Mock query builders for demonstration
struct UserQueryBuilder;

impl UserQueryBuilder {
    fn new() -> Self {
        Self
    }

    fn find_many(self) -> FindManyBuilder<User> {
        FindManyBuilder::new()
    }

    fn find_unique(self) -> FindUniqueBuilder<User> {
        FindUniqueBuilder::new()
    }

    fn find_first(self) -> FindFirstBuilder<User> {
        FindFirstBuilder::new()
    }

    fn create(self, _data: CreateData) -> CreateBuilder<User> {
        CreateBuilder::new()
    }

    fn update(self) -> UpdateBuilder<User> {
        UpdateBuilder::new()
    }

    fn delete(self) -> DeleteBuilder<User> {
        DeleteBuilder::new()
    }
}

struct PostQueryBuilder;

impl PostQueryBuilder {
    fn new() -> Self {
        Self
    }
}

// Generic query builders
struct FindManyBuilder<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> FindManyBuilder<T> {
    fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }

    #[allow(non_snake_case)]
    fn r#where(self, _filter: impl Into<String>) -> Self {
        self
    }

    fn order_by(self, _order: impl Into<String>) -> Self {
        self
    }

    fn skip(self, _count: usize) -> Self {
        self
    }

    fn take(self, _count: usize) -> Self {
        self
    }
}

impl FindManyBuilder<User> {
    async fn exec(self) -> Result<Vec<User>, Box<dyn std::error::Error>> {
        // In real implementation, this would execute the query
        Ok(vec![
            User {
                id: 1,
                email: "alice@example.com".to_string(),
                name: Some("Alice".to_string()),
                active: true,
                created_at: chrono::Utc::now(),
            },
            User {
                id: 2,
                email: "bob@example.com".to_string(),
                name: Some("Bob".to_string()),
                active: true,
                created_at: chrono::Utc::now(),
            },
        ])
    }
}

struct FindUniqueBuilder<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> FindUniqueBuilder<T> {
    fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }

    #[allow(non_snake_case)]
    fn r#where(self, _filter: impl Into<String>) -> Self {
        self
    }
}

impl FindUniqueBuilder<User> {
    async fn exec(self) -> Result<Option<User>, Box<dyn std::error::Error>> {
        Ok(Some(User {
            id: 1,
            email: "alice@example.com".to_string(),
            name: Some("Alice".to_string()),
            active: true,
            created_at: chrono::Utc::now(),
        }))
    }
}

struct FindFirstBuilder<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> FindFirstBuilder<T> {
    fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }

    #[allow(non_snake_case)]
    fn r#where(self, _filter: impl Into<String>) -> Self {
        self
    }
}

impl FindFirstBuilder<User> {
    async fn exec(self) -> Result<Option<User>, Box<dyn std::error::Error>> {
        Ok(Some(User {
            id: 1,
            email: "alice@company.com".to_string(),
            name: Some("Alice".to_string()),
            active: true,
            created_at: chrono::Utc::now(),
        }))
    }
}

struct CreateData {
    fields: std::collections::HashMap<String, String>,
}

impl CreateData {
    fn new() -> Self {
        Self {
            fields: std::collections::HashMap::new(),
        }
    }

    fn set(mut self, key: &str, value: impl ToString) -> Self {
        self.fields.insert(key.to_string(), value.to_string());
        self
    }
}

struct CreateBuilder<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> CreateBuilder<T> {
    fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }
}

impl CreateBuilder<User> {
    async fn exec(self) -> Result<User, Box<dyn std::error::Error>> {
        Ok(User {
            id: 3,
            email: "new@example.com".to_string(),
            name: Some("New User".to_string()),
            active: true,
            created_at: chrono::Utc::now(),
        })
    }
}

struct UpdateData {
    fields: std::collections::HashMap<String, String>,
}

impl UpdateData {
    fn new() -> Self {
        Self {
            fields: std::collections::HashMap::new(),
        }
    }

    fn set(mut self, key: &str, value: impl ToString) -> Self {
        self.fields.insert(key.to_string(), value.to_string());
        self
    }
}

struct UpdateBuilder<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> UpdateBuilder<T> {
    fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }

    #[allow(non_snake_case)]
    fn r#where(self, _filter: impl Into<String>) -> Self {
        self
    }

    fn data(self, _data: UpdateData) -> Self {
        self
    }
}

impl UpdateBuilder<User> {
    async fn exec(self) -> Result<User, Box<dyn std::error::Error>> {
        Ok(User {
            id: 1,
            email: "alice@example.com".to_string(),
            name: Some("Alice Updated".to_string()),
            active: true,
            created_at: chrono::Utc::now(),
        })
    }
}

struct DeleteBuilder<T> {
    _phantom: std::marker::PhantomData<T>,
}

impl<T> DeleteBuilder<T> {
    fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }

    #[allow(non_snake_case)]
    fn r#where(self, _filter: impl Into<String>) -> Self {
        self
    }
}

impl DeleteBuilder<User> {
    async fn exec(self) -> Result<User, Box<dyn std::error::Error>> {
        Ok(User {
            id: 1,
            email: "alice@example.com".to_string(),
            name: Some("Alice".to_string()),
            active: true,
            created_at: chrono::Utc::now(),
        })
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Prax Basic Query Examples ===\n");

    // Initialize the client
    let client = PraxClient::new("postgresql://localhost/prax_example").await?;

    // =========================================================================
    // FIND MANY - Query multiple records
    // =========================================================================
    println!("--- Find Many Users ---");

    let users = client
        .user()
        .find_many()
        .r#where(user::active::equals(true))
        .order_by(user::created_at::desc())
        .take(10)
        .exec()
        .await?;

    println!("Found {} active users:", users.len());
    for user in &users {
        println!(
            "  - {} ({})",
            user.email,
            user.name.as_deref().unwrap_or("No name")
        );
    }
    println!();

    // Find with multiple filters
    let filtered_users = client
        .user()
        .find_many()
        .r#where(user::email::contains("@example.com"))
        .r#where(user::active::equals(true))
        .skip(0)
        .take(5)
        .exec()
        .await?;

    println!(
        "Found {} users with @example.com emails",
        filtered_users.len()
    );
    println!();

    // =========================================================================
    // FIND UNIQUE - Query single record by unique field
    // =========================================================================
    println!("--- Find Unique User ---");

    let user = client
        .user()
        .find_unique()
        .r#where(user::id::equals(1))
        .exec()
        .await?;

    match user {
        Some(u) => println!("Found user: {} ({})", u.email, u.id),
        None => println!("User not found"),
    }
    println!();

    // =========================================================================
    // FIND FIRST - Query first matching record
    // =========================================================================
    println!("--- Find First User ---");

    let user = client
        .user()
        .find_first()
        .r#where(user::email::ends_with("@company.com"))
        .exec()
        .await?;

    match user {
        Some(u) => println!("Found first company user: {}", u.email),
        None => println!("No company users found"),
    }
    println!();

    // =========================================================================
    // CREATE - Insert new records
    // =========================================================================
    println!("--- Create User ---");

    let new_user = client
        .user()
        .create(
            CreateData::new()
                .set("email", "newuser@example.com")
                .set("name", "New User")
                .set("active", true),
        )
        .exec()
        .await?;

    println!("Created user: {} (id: {})", new_user.email, new_user.id);
    println!();

    // =========================================================================
    // UPDATE - Modify existing records
    // =========================================================================
    println!("--- Update User ---");

    let updated_user = client
        .user()
        .update()
        .r#where(user::id::equals(1))
        .data(UpdateData::new().set("name", "Alice Updated"))
        .exec()
        .await?;

    println!(
        "Updated user: {} -> {:?}",
        updated_user.email, updated_user.name
    );
    println!();

    // =========================================================================
    // DELETE - Remove records
    // =========================================================================
    println!("--- Delete User ---");

    let deleted_user = client
        .user()
        .delete()
        .r#where(user::id::equals(1))
        .exec()
        .await?;

    println!(
        "Deleted user: {} (id: {})",
        deleted_user.email, deleted_user.id
    );
    println!();

    println!("=== All examples completed successfully! ===");

    Ok(())
}
