use std::collections::HashMap;
use std::sync::Arc;

use anyhow::Result;
use async_trait::async_trait;
use sea_orm::DatabaseConnection;

use robson_core::plugin::{MessageEvent, ProcessEventKind, Worker};

use crate::commands::execute_bitbucket_repo_list;
use crate::config::WorkflowConfig;

pub struct BitbucketListWorker {
    workflow_db: DatabaseConnection,
    config: Arc<WorkflowConfig>,
}

impl BitbucketListWorker {
    pub const PATTERN: &'static str = r"(?i)(^<@\S+>\s*)?/bitbucket\s+list";

    pub fn new(workflow_db: DatabaseConnection, config: Arc<WorkflowConfig>) -> Self {
        Self {
            workflow_db,
            config,
        }
    }
}

#[async_trait]
impl Worker for BitbucketListWorker {
    fn name(&self) -> &'static str {
        "BitbucketListWorker"
    }

    fn description(&self) -> &'static str {
        "Fetch and upsert repositories from Bitbucket Cloud workspace."
    }

    fn example(&self) -> &'static str {
        "`/bitbucket list [workspace=<slug>]`"
    }

    async fn handle(
        &self,
        db: DatabaseConnection,
        msg: MessageEvent,
        args: HashMap<String, String>,
    ) -> Result<bool> {
        let workspace = args.get("workspace").cloned();

        let (kind, response) =
            match execute_bitbucket_repo_list(&self.config, workspace, &self.workflow_db).await {
                Ok(text) => (ProcessEventKind::Completed, text),
                Err(e) => (
                    ProcessEventKind::Failed,
                    format!(":x: Failed to list Bitbucket repositories: {:#}", e),
                ),
            };

        if let Some(conv_id) = msg.conversation_id {
            if let Err(e) = robson_core::entities::process_event::Model::insert(
                &db,
                conv_id,
                kind.as_str(),
                &response,
            )
            .await
            {
                tracing::warn!(error = %e, "failed to persist process event");
            }
        }

        Ok(true)
    }
}
