use crate::AppService;
use crate::error::AppError;
use models::projects::{MemberRole, project, project_history_name, project_members};
use models::repos::repo;
use sea_orm::*;
use session::Session;
use std::str::FromStr;
use uuid::Uuid;

impl AppService {
    pub async fn utils_find_project_by_name(
        &self,
        name: String,
    ) -> Result<project::Model, AppError> {
        match project::Entity::find()
            .filter(project::Column::Name.eq(name.clone()))
            .one(&self.db)
            .await
            .ok()
            .flatten()
        {
            Some(project) => Ok(project),
            None => match project_history_name::Entity::find()
                .filter(project_history_name::Column::HistoryName.eq(name))
                .one(&self.db)
                .await
                .ok()
                .flatten()
            {
                Some(project) => self.utils_find_project_by_uid(project.project_uid).await,
                None => Err(AppError::ProjectNotFound),
            },
        }
    }

    pub async fn utils_find_project_by_uid(&self, uid: Uuid) -> Result<project::Model, AppError> {
        project::Entity::find_by_id(uid)
            .one(&self.db)
            .await
            .ok()
            .flatten()
            .ok_or(AppError::ProjectNotFound)
    }

    pub async fn utils_check_project_permission(
        &self,
        project_id: &Uuid,
        user_id: Uuid,
        required_scopes: &[MemberRole],
    ) -> Result<(), AppError> {
        let member = project_members::Entity::find()
            .filter(project_members::Column::Project.eq(*project_id))
            .filter(project_members::Column::User.eq(user_id))
            .one(&self.db)
            .await?;

        if let Some(member) = member {
            for scope in required_scopes {
                if member.scope_role().ok() == Some(scope.clone()) {
                    return Ok(());
                }
            }
        }

        Err(AppError::NoPower)
    }
    pub async fn utils_project_context_role(
        &self,
        context: &Session,
        project_name: String,
    ) -> Result<MemberRole, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;
        let project = self.utils_find_project_by_name(project_name).await?;
        let members = project_members::Entity::find()
            .filter(project_members::Column::Project.eq(project.id))
            .filter(project_members::Column::User.eq(user_uid))
            .one(&self.db)
            .await
            .map_err(|_| AppError::InternalError)?
            .map(|m| m.scope);
        MemberRole::from_str(&members.ok_or(AppError::Unauthorized)?)
            .map_err(|_| AppError::RoleParseError)
    }

    pub async fn utils_find_repo_by_name(
        &self,
        project_uid: Uuid,
        repo_name: &str,
    ) -> Result<repo::Model, AppError> {
        repo::Entity::find()
            .filter(repo::Column::Project.eq(project_uid))
            .filter(repo::Column::RepoName.eq(repo_name))
            .one(&self.db)
            .await?
            .ok_or(AppError::NotFound(format!(
                "Repository '{}' not found",
                repo_name
            )))
    }

    pub async fn check_project_access(
        &self,
        project_uid: Uuid,
        user_uid: Uuid,
    ) -> Result<(), AppError> {
        let project = project::Entity::find_by_id(project_uid)
            .one(&self.db)
            .await
            .ok()
            .flatten()
            .ok_or(AppError::ProjectNotFound)?;

        // Public project - allow access
        if project.is_public {
            return Ok(());
        }

        // Private project - check membership
        let member = project_members::Entity::find()
            .filter(project_members::Column::Project.eq(project_uid))
            .filter(project_members::Column::User.eq(user_uid))
            .one(&self.db)
            .await?;

        if member.is_some() {
            Ok(())
        } else {
            Err(AppError::NoPower)
        }
    }
}
