use crate::parallel::dead_repo_blacklist::DeadRepoBlacklistConfig;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParallelPhase1Config {
    pub max_repo_sync_workers_global: usize,
    pub max_inflight_snapshot_bytes_global: usize,
    pub max_pending_repo_results: usize,
    /// Dead-repo transport blacklist (#141). `None` disables the feature
    /// entirely (default, behavior unchanged).
    pub dead_repo_blacklist: Option<DeadRepoBlacklistConfig>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParallelPhase2Config {
    pub object_workers: usize,
    pub worker_queue_capacity: usize,
    pub ready_batch_size: usize,
    pub ready_batch_wall_time_budget_ms: u64,
    pub object_result_drain_batch_size: usize,
    pub publication_point_finalize_batch_size: usize,
    pub publication_point_finalize_wall_time_budget_ms: u64,
    pub publication_point_finalize_queue_capacity: usize,
    /// Experimental: workers of the ready publication point stage pool. `0`
    /// disables the pool and keeps the inline compute+apply staging path.
    pub stage_workers: usize,
}

impl Default for ParallelPhase2Config {
    fn default() -> Self {
        Self {
            object_workers: 8,
            worker_queue_capacity: 256,
            ready_batch_size: 256,
            ready_batch_wall_time_budget_ms: 100,
            object_result_drain_batch_size: 2048,
            publication_point_finalize_batch_size: 256,
            publication_point_finalize_wall_time_budget_ms: 100,
            publication_point_finalize_queue_capacity: 32768,
            stage_workers: 0,
        }
    }
}

impl Default for ParallelPhase1Config {
    fn default() -> Self {
        Self {
            max_repo_sync_workers_global: 4,
            max_inflight_snapshot_bytes_global: 512 * 1024 * 1024,
            max_pending_repo_results: 1024,
            dead_repo_blacklist: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{ParallelPhase1Config, ParallelPhase2Config};

    #[test]
    fn default_parallel_phase1_config_is_bounded() {
        let cfg = ParallelPhase1Config::default();
        assert!(cfg.max_repo_sync_workers_global > 0);
        assert!(cfg.max_inflight_snapshot_bytes_global > 0);
        assert!(cfg.max_pending_repo_results > 0);
    }

    #[test]
    fn default_parallel_phase2_config_is_bounded() {
        let cfg = ParallelPhase2Config::default();
        assert!(cfg.object_workers > 0);
        assert!(cfg.worker_queue_capacity > 0);
        assert!(cfg.ready_batch_size > 0);
        assert!(cfg.ready_batch_wall_time_budget_ms > 0);
        assert!(cfg.object_result_drain_batch_size > 0);
        assert!(cfg.publication_point_finalize_batch_size > 0);
        assert!(cfg.publication_point_finalize_wall_time_budget_ms > 0);
        assert!(cfg.publication_point_finalize_queue_capacity > 0);
    }
}
