use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};

use serde_json::Value;

use crate::browser::backend::BrowserBackend;
use crate::browser::bridge_contract::{BridgeBrowserActionReply, BridgeBrowserActionRequest};
use crate::browser::bridge_transport::BridgeActionTransport;
use crate::pipe::{Action, CommandOutput, ExecutionSurfaceMetadata, PipeError};
use crate::security::MacPolicy;

pub struct BridgeBrowserBackend {
    transport: Arc<dyn BridgeActionTransport>,
    mac_policy: MacPolicy,
    next_seq: AtomicU64,
}

impl BridgeBrowserBackend {
    pub fn new(transport: Arc<dyn BridgeActionTransport>, mac_policy: MacPolicy) -> Self {
        Self {
            transport,
            mac_policy,
            next_seq: AtomicU64::new(1),
        }
    }
}

impl BrowserBackend for BridgeBrowserBackend {
    fn invoke(
        &self,
        action: Action,
        params: Value,
        expected_domain: &str,
    ) -> Result<CommandOutput, PipeError> {
        self.mac_policy.validate(&action, expected_domain)?;

        let seq = self.next_seq.fetch_add(1, Ordering::Relaxed);
        let reply = self.transport.execute(BridgeBrowserActionRequest::new(
            action.as_str(),
            params,
            expected_domain,
        ))?;

        match reply {
            BridgeBrowserActionReply::Success(success) => Ok(CommandOutput {
                seq,
                success: true,
                data: success.data,
                aom_snapshot: success.aom_snapshot,
                timing: success.timing,
            }),
            BridgeBrowserActionReply::Error(error) => Err(PipeError::Protocol(format!(
                "bridge action failed: {}",
                error.message
            ))),
        }
    }

    fn surface_metadata(&self) -> ExecutionSurfaceMetadata {
        self.mac_policy.privileged_surface_metadata()
    }

    fn supports_eval(&self) -> bool {
        self.mac_policy.supports_pipe_action(&Action::Eval)
    }
}
