use crate::AppService;
use crate::error::AppError;
use chrono::{DateTime, Utc};
use models::Decimal;
use models::projects::{MemberRole, project, project_audit_log, project_billing, project_members};
use models::workspaces::workspace_membership;
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
use uuid::Uuid;

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct ProjectInitParams {
    pub name: String,
    pub description: Option<String>,
    pub is_public: bool,
    /// Optional workspace slug to associate this project with.
    pub workspace_slug: Option<String>,
}

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct ProjectInitResponse {
    pub params: ProjectInitParams,
    pub project: ProjectModel,
}

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct ProjectModel {
    pub uid: Uuid,
    pub name: String,
    pub display_name: String,
    pub avatar_url: Option<String>,
    pub description: Option<String>,
    pub is_public: bool,
    pub workspace_id: Option<Uuid>,
    pub created_by: Uuid,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

impl AppService {
    pub async fn project_init(
        &self,
        ctx: &Session,
        params: ProjectInitParams,
    ) -> Result<ProjectInitResponse, AppError> {
        let inner = params.clone();
        if let Ok(_) = self.utils_find_project_by_name(params.name.clone()).await {
            return Err(AppError::ProjectNameAlreadyExists);
        }
        let user = ctx.user().ok_or(AppError::Unauthorized)?;
        let user = self.utils_find_user_by_uid(user).await?;

        // Resolve workspace if provided
        let workspace_id = match &params.workspace_slug {
            Some(slug) => {
                let ws = self.utils_find_workspace_by_slug(slug.clone()).await?;
                let membership = workspace_membership::Entity::find()
                    .filter(workspace_membership::Column::WorkspaceId.eq(ws.id))
                    .filter(workspace_membership::Column::UserId.eq(user.uid))
                    .filter(workspace_membership::Column::Status.eq("active"))
                    .one(&self.db)
                    .await?;
                if membership.is_none() {
                    return Err(AppError::NotWorkspaceMember);
                }
                Some(ws.id)
            }
            None => None,
        };

        let project_uid = Uuid::now_v7();
        let txn = self.db.begin().await?;
        let project = project::ActiveModel {
            id: Set(project_uid),
            name: Set(params.name.clone()),
            display_name: Set(params.name),
            avatar_url: Set(None),
            description: Set(params.description),
            is_public: Set(params.is_public),
            created_by: Set(user.uid),
            workspace_id: Set(workspace_id),
            created_at: Set(Utc::now()),
            updated_at: Set(Utc::now()),
        };
        let _project = project.insert(&txn).await?;

        let project_member = project_members::ActiveModel {
            id: Default::default(),
            project: Set(_project.id),
            user: Set(user.uid),
            scope: Set(MemberRole::Owner.to_string()),
            joined_at: Set(Utc::now()),
        };
        project_member.insert(&txn).await?;

        let billing = project_billing::ActiveModel {
            project: Set(_project.id),
            balance: Set(Decimal::from(200i64)),
            currency: Set("USD".to_string()),
            user: Set(Some(user.uid)),
            updated_at: Set(Utc::now()),
            created_at: Set(Utc::now()),
            ..Default::default()
        };
        billing.insert(&txn).await?;

        let log = project_audit_log::ActiveModel {
            project: Set(_project.id),
            actor: Set(user.uid),
            action: Set("project_create".to_string()),
            details: Set(Some(serde_json::json!({
                "project_name": _project.name.clone(),
                "project_uid": _project.id,
                "is_public": _project.is_public,
                "description": _project.description.clone(),
            }))),
            created_at: Set(Utc::now()),
            ..Default::default()
        };
        log.insert(&txn).await?;

        txn.commit().await?;
        Ok(ProjectInitResponse {
            params: inner,
            project: ProjectModel {
                uid: _project.id,
                name: _project.name.clone(),
                display_name: _project.display_name.clone(),
                avatar_url: _project.avatar_url.clone(),
                description: _project.description.clone(),
                is_public: _project.is_public,
                workspace_id: _project.workspace_id,
                created_by: _project.created_by,
                created_at: _project.created_at,
                updated_at: _project.updated_at,
            },
        })
    }
}
