// SPDX-FileCopyrightText: 2025-2026 RAprogramm <andrey.rozanov.vl@gmail.com>
// SPDX-License-Identifier: MIT

//! `PostgreSQL` repository implementation generator.
//!
//! Generates `impl {Name}Repository for sqlx::PgPool` with complete CRUD
//! operations. This is the primary database backend, providing full SQL support
//! via sqlx.
//!
//! # Module Structure
//!
//! ```text
//! postgres/
//! ├── mod.rs         — Main generator and public API
//! ├── context.rs     — Generation context with precomputed values
//! ├── crud.rs        — CREATE, READ, UPDATE, DELETE, LIST methods
//! ├── query.rs       — Type-safe query filtering method
//! ├── relations.rs   — belongs_to and has_many relation methods
//! ├── projections.rs — Optimized projection SELECT methods
//! ├── soft_delete.rs — Soft delete support methods
//! ├── lookup.rs      — find_by_/exists_by_ lookup methods
//! └── helpers.rs     — SQL building helper functions
//! ```
//!
//! # Generated Implementation
//!
//! ```rust,ignore
//! #[async_trait]
//! impl UserRepository for sqlx::PgPool {
//!     type Error = sqlx::Error;
//!     type Pool = sqlx::PgPool;
//!
//!     fn pool(&self) -> &Self::Pool { self }
//!
//!     // CRUD methods
//!     async fn create(&self, dto: CreateUserRequest) -> Result<User, Self::Error>;
//!     async fn find_by_id(&self, id: Uuid) -> Result<Option<User>, Self::Error>;
//!     async fn update(&self, id: Uuid, dto: UpdateUserRequest) -> Result<User, Self::Error>;
//!     async fn delete(&self, id: Uuid) -> Result<bool, Self::Error>;
//!     async fn list(&self, limit: i64, offset: i64) -> Result<Vec<User>, Self::Error>;
//!
//!     // Query method (if #[filter] used)
//!     async fn query(&self, query: UserQuery) -> Result<Vec<User>, Self::Error>;
//!
//!     // Relation methods
//!     async fn find_organization(&self, id: Uuid) -> Result<Option<Organization>, Self::Error>;
//!     async fn find_posts(&self, user_id: Uuid) -> Result<Vec<Post>, Self::Error>;
//!
//!     // Projection methods
//!     async fn find_by_id_public(&self, id: Uuid) -> Result<Option<UserPublic>, Self::Error>;
//!
//!     // Soft delete methods (if soft_delete enabled)
//!     async fn hard_delete(&self, id: Uuid) -> Result<bool, Self::Error>;
//!     async fn restore(&self, id: Uuid) -> Result<bool, Self::Error>;
//! }
//! ```
//!
//! # Feature Flag
//!
//! The implementation is emitted only when the facade's `postgres`
//! feature is enabled at expansion time; consumer crates never see the
//! cfg.

mod bulk;
mod constraints;
mod context;
mod crud;
mod lookup;
mod notify;
mod outbox;
mod projections;
mod query;
mod relations;
mod save;
mod scoped;
mod soft_delete;
mod upsert;

pub mod helpers;

pub use context::Context;
use proc_macro2::TokenStream;
use quote::quote;

use crate::{entity::parse::EntityDef, utils::marker};

/// Generate `PostgreSQL` repository implementation.
///
/// Creates `impl {Name}Repository for sqlx::PgPool` with all CRUD methods,
/// relation methods, projection methods, query method, soft delete methods,
/// and lookup methods for unique/indexed columns.
///
/// # Generated Methods
///
/// | Category | Methods |
/// |----------|---------|
/// | CRUD | `create`, `find_by_id`, `update`, `delete`, `list` |
/// | Query | `query` (if entity has `#[filter]` fields) |
/// | Lookup | `find_by_{field}`, `exists_by_{field}` (if `#[column(unique/index)]`) |
/// | Relations | `find_{parent}`, `find_{children}` |
/// | Projections | `find_by_id_{projection}` |
/// | Soft Delete | `hard_delete`, `restore`, `*_with_deleted` |
pub fn generate(entity: &EntityDef) -> TokenStream {
    if !cfg!(feature = "postgres") {
        return TokenStream::new();
    }

    let ctx = Context::new(entity);
    let trait_name = &ctx.trait_name;
    let error_type = entity.error_type();

    let create_impl = ctx.create_method();
    let upsert_impl = ctx.upsert_method();
    let find_impl = ctx.find_by_id_method();
    let update_impl = ctx.update_method();
    let delete_impl = ctx.delete_method();
    let list_impl = ctx.list_method();
    let list_after_impl = ctx.list_after_method();
    let find_by_ids_impl = ctx.find_by_ids_method();
    let create_many_impl = ctx.create_many_method();
    let delete_many_impl = ctx.delete_many_method();
    let query_impl = ctx.query_method();
    let stream_impl = ctx.stream_filtered_method();
    let relation_impls = ctx.relation_methods();
    let projection_impls = ctx.projection_methods();
    let soft_delete_impls = ctx.soft_delete_methods();
    let scoped_impls = ctx.scoped_methods();
    let lookup_impls = ctx.lookup_methods();
    let save_impl = ctx.save_method();
    let constraint_mapper = ctx.constraint_mapper();
    let marker = marker::generated();

    quote! {
        #marker
        #constraint_mapper

        #[async_trait::async_trait]
        impl #trait_name for sqlx::PgPool {
            type Error = #error_type;
            type Pool = sqlx::PgPool;

            fn pool(&self) -> &Self::Pool {
                self
            }

            #create_impl
            #upsert_impl
            #find_impl
            #update_impl
            #delete_impl
            #list_impl
            #list_after_impl
            #find_by_ids_impl
            #create_many_impl
            #delete_many_impl
            #query_impl
            #stream_impl
            #lookup_impls
            #relation_impls
            #projection_impls
            #soft_delete_impls
            #scoped_impls
            #save_impl
        }
    }
}
