use crate::{EntityTrait, QuerySelect, RelationDef, Select, join_tbl_on_condition};
use sea_query::{Condition, IntoIden, JoinType};

/// Same as [RelationDef]
pub type LinkDef = RelationDef;

/// A Trait for links between Entities
pub trait Linked {
    #[allow(missing_docs)]
    type FromEntity: EntityTrait;

    #[allow(missing_docs)]
    type ToEntity: EntityTrait;

    /// Link for an Entity
    fn link(&self) -> Vec<LinkDef>;

    /// Find all the Entities that are linked to the Entity
    fn find_linked(&self) -> Select<Self::ToEntity> {
        let mut select = Select::new();
        for (i, mut rel) in self.link().into_iter().rev().enumerate() {
            let from_tbl = format!("r{i}").into_iden();
            let to_tbl = if i > 0 {
                format!("r{}", i - 1).into_iden()
            } else {
                rel.to_tbl.sea_orm_table().clone()
            };
            let table_ref = rel.from_tbl;

            let mut condition = Condition::all().add(join_tbl_on_condition(
                from_tbl.clone(),
                to_tbl.clone(),
                rel.from_col,
                rel.to_col,
            ));
            if let Some(f) = rel.on_condition.take() {
                condition = condition.add(f(from_tbl.clone(), to_tbl.clone()));
            }

            select
                .query()
                .join_as(JoinType::InnerJoin, table_ref, from_tbl, condition);
        }
        select
    }
}
