use crate::AppService;
use crate::error::AppError;
use chrono::Utc;
use models::Decimal;
use models::WorkspaceRole;
use models::workspaces::workspace;
use models::workspaces::workspace_billing;
use models::workspaces::workspace_membership;
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct WorkspaceInitParams {
    pub slug: String,
    pub name: String,
    pub description: Option<String>,
}

impl AppService {
    pub async fn workspace_init(
        &self,
        ctx: &Session,
        params: WorkspaceInitParams,
    ) -> Result<workspace::Model, AppError> {
        let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
        let user = self.utils_find_user_by_uid(user_uid).await?;

        // Validate slug format: alphanumeric, dashes, underscores
        if !params
            .slug
            .chars()
            .all(|c| c.is_alphanumeric() || c == '-' || c == '_')
        {
            return Err(AppError::BadRequest(
                "Slug must contain only letters, numbers, hyphens and underscores".to_string(),
            ));
        }

        // Check slug uniqueness
        if workspace::Entity::find()
            .filter(workspace::Column::Slug.eq(&params.slug))
            .filter(workspace::Column::DeletedAt.is_null())
            .one(&self.db)
            .await?
            .is_some()
        {
            return Err(AppError::WorkspaceSlugAlreadyExists);
        }

        // Check name uniqueness
        if workspace::Entity::find()
            .filter(workspace::Column::Name.eq(&params.name))
            .filter(workspace::Column::DeletedAt.is_null())
            .one(&self.db)
            .await?
            .is_some()
        {
            return Err(AppError::WorkspaceNameAlreadyExists);
        }

        let txn = self.db.begin().await?;

        let ws = workspace::ActiveModel {
            id: Set(Uuid::now_v7()),
            slug: Set(params.slug),
            name: Set(params.name),
            description: Set(params.description),
            avatar_url: Set(None),
            plan: Set("free".to_string()),
            billing_email: Set(None),
            stripe_customer_id: Set(None),
            stripe_subscription_id: Set(None),
            plan_expires_at: Set(None),
            deleted_at: Set(None),
            created_at: Set(Utc::now()),
            updated_at: Set(Utc::now()),
        };
        let ws = ws.insert(&txn).await?;

        let membership = workspace_membership::ActiveModel {
            id: Default::default(),
            workspace_id: Set(ws.id),
            user_id: Set(user.uid),
            role: Set(WorkspaceRole::Owner.to_string()),
            status: Set("active".to_string()),
            invited_by: Set(None),
            joined_at: Set(Utc::now()),
            invite_token: Set(None),
            invite_expires_at: Set(None),
        };
        membership.insert(&txn).await?;

        // Create billing record — only first workspace gets $30 initial balance
        let existing_workspaces = workspace_membership::Entity::find()
            .filter(workspace_membership::Column::UserId.eq(user.uid))
            .filter(workspace_membership::Column::Status.eq("active"))
            .all(&self.db)
            .await?;
        let initial_balance = if existing_workspaces.len() <= 1 {
            Decimal::from_f64_retain(30.0).unwrap_or(Decimal::ZERO)
        } else {
            Decimal::ZERO
        };
        let billing = workspace_billing::ActiveModel {
            workspace_id: Set(ws.id),
            balance: Set(initial_balance),
            currency: Set("USD".to_string()),
            monthly_quota: Set(Decimal::from_f64_retain(100.0).unwrap_or(Decimal::ZERO)),
            total_spent: Set(Decimal::ZERO),
            updated_at: Set(Utc::now()),
            created_at: Set(Utc::now()),
        };
        billing.insert(&txn).await?;

        txn.commit().await?;
        Ok(ws)
    }
}

use uuid::Uuid;
