use crate::common::PostgresSchemaType;
use crate::helpers;
use crate::traits::PostgresTable;
use crate::values::PostgresValue;
use core::fmt::Debug;
use core::marker::PhantomData;
use drizzle_core::ToSQL;
use drizzle_core::traits::SQLTable;
use paste::paste;

// Import the ExecutableState trait
use super::ExecutableState;

//------------------------------------------------------------------------------
// Type State Markers
//------------------------------------------------------------------------------

/// Marker for the initial state of `SelectBuilder`.
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectInitial;

/// Marker for the state after FROM clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectFromSet;

/// Marker for the state after JOIN clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectJoinSet;

/// Marker for the state after WHERE clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectWhereSet;

/// Marker for the state after GROUP BY clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectGroupSet;

/// Marker for the state after ORDER BY clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectOrderSet;

/// Marker for the state after LIMIT clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectLimitSet;

/// Marker for the state after OFFSET clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectOffsetSet;

/// Marker for the state after set operations (UNION/INTERSECT/EXCEPT)
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectSetOpSet;

/// Marker for the state after FOR UPDATE/SHARE clause
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectForSet;

//------------------------------------------------------------------------------
// Join macros (generates all join variants)
//------------------------------------------------------------------------------

#[doc(hidden)]
macro_rules! join_impl {
    () => {
        join_impl!(natural, Join::new().natural(), drizzle_core::AfterJoin);
        join_impl!(natural_left, Join::new().natural().left(), drizzle_core::AfterLeftJoin);
        join_impl!(left, Join::new().left(), drizzle_core::AfterLeftJoin);
        join_impl!(left_outer, Join::new().left().outer(), drizzle_core::AfterLeftJoin);
        join_impl!(natural_left_outer, Join::new().natural().left().outer(), drizzle_core::AfterLeftJoin);
        join_impl!(natural_right, Join::new().natural().right(), drizzle_core::AfterRightJoin);
        join_impl!(right, Join::new().right(), drizzle_core::AfterRightJoin);
        join_impl!(right_outer, Join::new().right().outer(), drizzle_core::AfterRightJoin);
        join_impl!(natural_right_outer, Join::new().natural().right().outer(), drizzle_core::AfterRightJoin);
        join_impl!(natural_full, Join::new().natural().full(), drizzle_core::AfterFullJoin);
        join_impl!(full, Join::new().full(), drizzle_core::AfterFullJoin);
        join_impl!(full_outer, Join::new().full().outer(), drizzle_core::AfterFullJoin);
        join_impl!(natural_full_outer, Join::new().natural().full().outer(), drizzle_core::AfterFullJoin);
        join_impl!(inner, Join::new().inner(), drizzle_core::AfterJoin);
        join_impl!(cross, Join::new().cross(), drizzle_core::AfterJoin);

        // USING variants only for non-natural, non-cross joins
        join_using_impl!(left, drizzle_core::AfterLeftJoin);
        join_using_impl!(left_outer, drizzle_core::AfterLeftJoin);
        join_using_impl!(right, drizzle_core::AfterRightJoin);
        join_using_impl!(right_outer, drizzle_core::AfterRightJoin);
        join_using_impl!(full, drizzle_core::AfterFullJoin);
        join_using_impl!(full_outer, drizzle_core::AfterFullJoin);
        join_using_impl!(inner, drizzle_core::AfterJoin);
        join_using_impl!(); // Plain JOIN
    };
    ($type:ident, $join_expr:expr, $join_trait:path) => {
        paste! {
            /// JOIN with ON clause
            pub fn [<$type _join>]<J: crate::helpers::JoinArg<'a, T>>(
                self,
                arg: J,
            ) -> SelectBuilder<'a, S, SelectJoinSet, J::JoinedTable, <M as drizzle_core::ScopePush<J::JoinedTable>>::Out, <M as $join_trait<R, J::JoinedTable>>::NewRow, G>
            where
                M: $join_trait<R, J::JoinedTable> + drizzle_core::ScopePush<J::JoinedTable>,
            {
                use drizzle_core::Join;
                SelectBuilder {
                    sql: self.sql.append(arg.into_join_sql($join_expr)),
                    schema: PhantomData,
                    state: PhantomData,
                    table: PhantomData,
                    marker: PhantomData,
                    row: PhantomData,
                    grouped: PhantomData,
                }
            }
        }
    };
}

macro_rules! join_using_impl {
    () => {
        /// JOIN with USING clause (PostgreSQL-specific)
        pub fn join_using<U: PostgresTable<'a>>(
            self,
            table: U,
            columns: impl ToSQL<'a, PostgresValue<'a>>,
        ) -> SelectBuilder<
            'a,
            S,
            SelectJoinSet,
            U,
            <M as drizzle_core::ScopePush<U>>::Out,
            <M as drizzle_core::AfterJoin<R, U>>::NewRow,
            G,
        >
        where
            M: drizzle_core::AfterJoin<R, U> + drizzle_core::ScopePush<U>,
        {
            SelectBuilder {
                sql: self.sql.append(helpers::join_using(table, columns)),
                schema: PhantomData,
                state: PhantomData,
                table: PhantomData,
                marker: PhantomData,
                row: PhantomData,
                grouped: PhantomData,
            }
        }
    };
    ($type:ident, $join_trait:path) => {
        paste! {
            /// JOIN with USING clause (PostgreSQL-specific)
            pub fn [<$type _join_using>]<U: PostgresTable<'a>>(
                self,
                table: U,
                columns: impl ToSQL<'a, PostgresValue<'a>>,
            ) -> SelectBuilder<
                'a,
                S,
                SelectJoinSet,
                U,
                <M as drizzle_core::ScopePush<U>>::Out,
                <M as $join_trait<R, U>>::NewRow,
                G,
            >
            where
                M: $join_trait<R, U> + drizzle_core::ScopePush<U>,
            {
                SelectBuilder {
                    sql: self.sql.append(helpers::[<$type _join_using>](table, columns)),
                    schema: PhantomData,
                    state: PhantomData,
                    table: PhantomData,
                    marker: PhantomData,
                    row: PhantomData,
                    grouped: PhantomData,
                }
            }
        }
    };
}

//------------------------------------------------------------------------------
// Capability trait impls for each state
//------------------------------------------------------------------------------

// ExecutableState
impl ExecutableState for SelectFromSet {}
impl ExecutableState for SelectWhereSet {}
impl ExecutableState for SelectLimitSet {}
impl ExecutableState for SelectOffsetSet {}
impl ExecutableState for SelectOrderSet {}
impl ExecutableState for SelectGroupSet {}
impl ExecutableState for SelectJoinSet {}
impl ExecutableState for SelectSetOpSet {}
impl ExecutableState for SelectForSet {}

// WhereAllowed
impl drizzle_core::WhereAllowed for SelectFromSet {}
impl drizzle_core::WhereAllowed for SelectJoinSet {}

// GroupByAllowed
impl drizzle_core::GroupByAllowed for SelectFromSet {}
impl drizzle_core::GroupByAllowed for SelectJoinSet {}
impl drizzle_core::GroupByAllowed for SelectWhereSet {}

// OrderByAllowed
impl drizzle_core::OrderByAllowed for SelectFromSet {}
impl drizzle_core::OrderByAllowed for SelectJoinSet {}
impl drizzle_core::OrderByAllowed for SelectWhereSet {}
impl drizzle_core::OrderByAllowed for SelectGroupSet {}
impl drizzle_core::OrderByAllowed for SelectSetOpSet {}

// LimitAllowed
impl drizzle_core::LimitAllowed for SelectFromSet {}
impl drizzle_core::LimitAllowed for SelectJoinSet {}
impl drizzle_core::LimitAllowed for SelectWhereSet {}
impl drizzle_core::LimitAllowed for SelectGroupSet {}
impl drizzle_core::LimitAllowed for SelectOrderSet {}
impl drizzle_core::LimitAllowed for SelectSetOpSet {}

// OffsetAllowed
impl drizzle_core::OffsetAllowed for SelectFromSet {}
impl drizzle_core::OffsetAllowed for SelectLimitSet {}
impl drizzle_core::OffsetAllowed for SelectSetOpSet {}

// JoinAllowed
impl drizzle_core::JoinAllowed for SelectFromSet {}
impl drizzle_core::JoinAllowed for SelectJoinSet {}

// HavingAllowed
impl drizzle_core::HavingAllowed for SelectGroupSet {}

// GroupByApplied (for aggregate/scalar mixing enforcement)
impl drizzle_core::GroupByApplied for SelectGroupSet {}
impl drizzle_core::GroupByApplied for SelectOrderSet {}
impl drizzle_core::GroupByApplied for SelectLimitSet {}
impl drizzle_core::GroupByApplied for SelectOffsetSet {}
impl drizzle_core::GroupByApplied for SelectSetOpSet {}

#[doc(hidden)]
pub trait AsCteState {}

impl AsCteState for SelectFromSet {}
impl AsCteState for SelectJoinSet {}
impl AsCteState for SelectWhereSet {}
impl AsCteState for SelectGroupSet {}
impl AsCteState for SelectOrderSet {}
impl AsCteState for SelectLimitSet {}
impl AsCteState for SelectOffsetSet {}

//------------------------------------------------------------------------------
// SelectBuilder Definition
//------------------------------------------------------------------------------

/// Builds a SELECT query specifically for `PostgreSQL`
pub type SelectBuilder<'a, Schema, State, Table = (), Marker = (), Row = (), Grouped = ()> =
    super::QueryBuilder<'a, Schema, State, Table, Marker, Row, Grouped>;

//------------------------------------------------------------------------------
// Initial State: .from()
//------------------------------------------------------------------------------

impl<'a, S, M> SelectBuilder<'a, S, SelectInitial, (), M> {
    /// Specifies the table to select FROM and transitions state.
    #[inline]
    #[allow(clippy::type_complexity)]
    pub fn from<T>(
        self,
        query: T,
    ) -> SelectBuilder<
        'a,
        S,
        SelectFromSet,
        T,
        drizzle_core::Scoped<M, drizzle_core::Cons<T, drizzle_core::Nil>>,
        <M as drizzle_core::ResolveRow<T>>::Row,
    >
    where
        T: ToSQL<'a, PostgresValue<'a>>,
        M: drizzle_core::ResolveRow<T>,
    {
        SelectBuilder {
            sql: self.sql.append(helpers::from(query)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

//------------------------------------------------------------------------------
// Capability-gated methods (generic over State)
//------------------------------------------------------------------------------

// JOIN (available from SelectFromSet and SelectJoinSet)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::JoinAllowed,
{
    /// Adds an INNER JOIN clause to the query.
    #[inline]
    #[allow(clippy::type_complexity)]
    pub fn join<J: crate::helpers::JoinArg<'a, T>>(
        self,
        arg: J,
    ) -> SelectBuilder<
        'a,
        S,
        SelectJoinSet,
        J::JoinedTable,
        <M as drizzle_core::ScopePush<J::JoinedTable>>::Out,
        <M as drizzle_core::AfterJoin<R, J::JoinedTable>>::NewRow,
        G,
    >
    where
        M: drizzle_core::AfterJoin<R, J::JoinedTable> + drizzle_core::ScopePush<J::JoinedTable>,
    {
        use drizzle_core::Join;
        SelectBuilder {
            sql: self.sql.append(arg.into_join_sql(Join::new())),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    join_impl!();
}

// WHERE (available from SelectFromSet and SelectJoinSet)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::WhereAllowed,
{
    /// Adds a WHERE clause to filter query results.
    #[inline]
    pub fn r#where<E>(self, condition: E) -> SelectBuilder<'a, S, SelectWhereSet, T, M, R, G>
    where
        E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
        E::SQLType: drizzle_core::types::BooleanLike,
    {
        SelectBuilder {
            sql: self.sql.append(helpers::r#where(condition)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

// GROUP BY (available from SelectFromSet, SelectJoinSet, SelectWhereSet)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::GroupByAllowed,
{
    /// Adds a GROUP BY clause to the query.
    pub fn group_by<Gr>(
        self,
        columns: Gr,
    ) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, Gr::Columns>
    where
        Gr: drizzle_core::IntoGroupBy<'a, PostgresValue<'a>>,
    {
        SelectBuilder {
            sql: self.sql.append(helpers::group_by_expr(columns)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

// HAVING (available only from SelectGroupSet)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::HavingAllowed,
{
    /// Adds a HAVING clause after GROUP BY.
    pub fn having<E>(self, condition: E) -> SelectBuilder<'a, S, SelectGroupSet, T, M, R, G>
    where
        E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
        E::SQLType: drizzle_core::types::BooleanLike,
    {
        SelectBuilder {
            sql: self.sql.append(helpers::having(condition)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

// ORDER BY (available from many states)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::OrderByAllowed,
{
    /// Sorts the query results.
    #[inline]
    pub fn order_by<TOrderBy>(
        self,
        expressions: TOrderBy,
    ) -> SelectBuilder<'a, S, SelectOrderSet, T, M, R, G>
    where
        TOrderBy: ToSQL<'a, PostgresValue<'a>>,
    {
        SelectBuilder {
            sql: self.sql.append(helpers::order_by(expressions)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

// LIMIT (available from many states)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::LimitAllowed,
{
    /// Limits the number of rows returned.
    #[inline]
    #[must_use]
    pub fn limit(self, limit: usize) -> SelectBuilder<'a, S, SelectLimitSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::limit(limit)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

// OFFSET (available from SelectFromSet, SelectLimitSet, SelectSetOpSet)
impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: drizzle_core::OffsetAllowed,
{
    /// Sets the offset for the query results.
    #[inline]
    #[must_use]
    pub fn offset(self, offset: usize) -> SelectBuilder<'a, S, SelectOffsetSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::offset(offset)),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

//------------------------------------------------------------------------------
// CTE support
//------------------------------------------------------------------------------

impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: AsCteState,
    T: SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>,
{
    /// Converts this SELECT query into a typed CTE using alias tag name.
    #[inline]
    #[must_use]
    pub fn into_cte<Tag: drizzle_core::Tag + 'static>(
        self,
    ) -> super::CTEView<
        'a,
        <T as SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>>::Aliased<Tag>,
        Self,
    > {
        let name = Tag::NAME;
        super::CTEView::new(
            <T as SQLTable<'a, PostgresSchemaType, PostgresValue<'a>>>::alias::<Tag>(),
            name,
            self,
        )
    }
}

//------------------------------------------------------------------------------
// Set operation support (UNION / INTERSECT / EXCEPT)
//------------------------------------------------------------------------------

impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: ExecutableState,
{
    /// Combines this query with another using UNION.
    pub fn union(
        self,
        other: impl IntoSelect<'a, S, M, R>,
    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
        SelectBuilder {
            sql: helpers::union(self.sql, other.into_select()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Combines this query with another using UNION ALL.
    pub fn union_all(
        self,
        other: impl IntoSelect<'a, S, M, R>,
    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
        SelectBuilder {
            sql: helpers::union_all(self.sql, other.into_select()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Combines this query with another using INTERSECT.
    pub fn intersect(
        self,
        other: impl IntoSelect<'a, S, M, R>,
    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
        SelectBuilder {
            sql: helpers::intersect(self.sql, other.into_select()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Combines this query with another using INTERSECT ALL.
    pub fn intersect_all(
        self,
        other: impl IntoSelect<'a, S, M, R>,
    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
        SelectBuilder {
            sql: helpers::intersect_all(self.sql, other.into_select()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Combines this query with another using EXCEPT.
    pub fn except(
        self,
        other: impl IntoSelect<'a, S, M, R>,
    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
        SelectBuilder {
            sql: helpers::except(self.sql, other.into_select()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Combines this query with another using EXCEPT ALL.
    pub fn except_all(
        self,
        other: impl IntoSelect<'a, S, M, R>,
    ) -> SelectBuilder<'a, S, SelectSetOpSet, T, M, R, G> {
        SelectBuilder {
            sql: helpers::except_all(self.sql, other.into_select()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

//------------------------------------------------------------------------------
// Expr impl for subquery usage
//------------------------------------------------------------------------------

impl<'a, S, State, T, M, R, G> drizzle_core::expr::Expr<'a, PostgresValue<'a>>
    for SelectBuilder<'a, S, State, T, M, R, G>
where
    State: ExecutableState,
    M: drizzle_core::expr::SubqueryType<'a, PostgresValue<'a>>,
{
    type SQLType = <M as drizzle_core::expr::SubqueryType<'a, PostgresValue<'a>>>::SQLType;
    type Nullable = drizzle_core::expr::Null;
    type Aggregate = drizzle_core::expr::Scalar;
}

//------------------------------------------------------------------------------
// IntoSelect conversion trait
//------------------------------------------------------------------------------

/// Conversion trait for types that can become a `SelectBuilder`.
/// Used by set operations to accept both raw `SelectBuilder` and `DrizzleBuilder`.
pub trait IntoSelect<'a, S, M, R> {
    type State: ExecutableState;
    type Table;
    fn into_select(self) -> SelectBuilder<'a, S, Self::State, Self::Table, M, R>;
}

impl<'a, S, State: ExecutableState, T, M, R, G> IntoSelect<'a, S, M, R>
    for SelectBuilder<'a, S, State, T, M, R, G>
{
    type State = State;
    type Table = T;
    fn into_select(self) -> SelectBuilder<'a, S, State, T, M, R> {
        SelectBuilder {
            sql: self.sql,
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

//------------------------------------------------------------------------------
// FOR UPDATE/SHARE Row Locking (PostgreSQL-specific)
//------------------------------------------------------------------------------

/// Trait for states that can have FOR UPDATE/SHARE clauses applied.
pub trait ForLockableState {}

impl ForLockableState for SelectFromSet {}
impl ForLockableState for SelectWhereSet {}
impl ForLockableState for SelectOrderSet {}
impl ForLockableState for SelectLimitSet {}
impl ForLockableState for SelectOffsetSet {}
impl ForLockableState for SelectJoinSet {}
impl ForLockableState for SelectGroupSet {}

impl<'a, S, State, T, M, R, G> SelectBuilder<'a, S, State, T, M, R, G>
where
    State: ForLockableState,
{
    /// Adds FOR UPDATE clause to lock selected rows for update.
    #[must_use]
    pub fn for_update(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::for_update()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Adds FOR SHARE clause to lock selected rows for shared access.
    #[must_use]
    pub fn for_share(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::for_share()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Adds FOR NO KEY UPDATE clause.
    #[must_use]
    pub fn for_no_key_update(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::for_no_key_update()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Adds FOR KEY SHARE clause.
    #[must_use]
    pub fn for_key_share(self) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::for_key_share()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Adds FOR UPDATE OF table clause.
    pub fn for_update_of<U: PostgresTable<'a>>(
        self,
        table: U,
    ) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::for_update_of(table.name())),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Adds FOR SHARE OF table clause.
    pub fn for_share_of<U: PostgresTable<'a>>(
        self,
        table: U,
    ) -> SelectBuilder<'a, S, SelectForSet, T, M, R, G> {
        SelectBuilder {
            sql: self.sql.append(helpers::for_share_of(table.name())),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

//------------------------------------------------------------------------------
// Post-FOR State Implementation (NOWAIT / SKIP LOCKED)
//------------------------------------------------------------------------------

impl<S, T, M, R, G> SelectBuilder<'_, S, SelectForSet, T, M, R, G> {
    /// Adds NOWAIT option to fail immediately if rows are locked.
    #[must_use]
    pub fn nowait(self) -> Self {
        SelectBuilder {
            sql: self.sql.append(helpers::nowait()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }

    /// Adds SKIP LOCKED option to skip over locked rows.
    #[must_use]
    pub fn skip_locked(self) -> Self {
        SelectBuilder {
            sql: self.sql.append(helpers::skip_locked()),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use drizzle_core::{SQL, ToSQL};

    #[test]
    fn test_select_builder_creation() {
        let builder = SelectBuilder::<(), SelectInitial> {
            sql: SQL::raw("SELECT *"),
            schema: PhantomData,
            state: PhantomData,
            table: PhantomData,
            marker: PhantomData,
            row: PhantomData,
            grouped: PhantomData,
        };

        assert_eq!(builder.to_sql().sql(), "SELECT *");
    }
}
