use crate::clone_events::{CloneEventLevel, CloneJobEvent};
use crate::clone_jobs::{
    CloneJobDetail, CloneJobId, CloneJobPhase, CloneJobRecord, CloneJobRequest, CloneJobStatus,
    CloneJobSummary,
};
use crate::{
    CloneJobRepository, ControlPlaneError, ControlPlaneSchemaService, DaemonId, LeaseToken,
};
use serde_json::Value;
use sqlx::PgPool;

pub struct CloneJobService {
    repository: CloneJobRepository,
}

impl CloneJobService {
    pub async fn new(pool: PgPool) -> Result<Self, ControlPlaneError> {
        ControlPlaneSchemaService::ensure_clone_tables(&pool).await?;
        Ok(Self {
            repository: CloneJobRepository::new(pool),
        })
    }

    pub fn repository(&self) -> &CloneJobRepository {
        &self.repository
    }

    pub async fn create_job(
        &self,
        request: CloneJobRequest,
    ) -> Result<CloneJobRecord, ControlPlaneError> {
        self.repository.create_job(request).await
    }

    pub async fn list_jobs(&self) -> Result<Vec<CloneJobSummary>, ControlPlaneError> {
        self.repository.list_jobs().await
    }

    pub async fn get_job(
        &self,
        job_id: CloneJobId,
    ) -> Result<Option<CloneJobDetail>, ControlPlaneError> {
        self.repository.get_job(job_id).await
    }

    pub async fn get_job_record(
        &self,
        job_id: CloneJobId,
    ) -> Result<Option<CloneJobRecord>, ControlPlaneError> {
        self.repository.get_job_record(job_id).await
    }

    pub async fn list_job_events(
        &self,
        job_id: CloneJobId,
    ) -> Result<Vec<CloneJobEvent>, ControlPlaneError> {
        self.repository.list_job_events(job_id).await
    }

    pub async fn cancel_job(
        &self,
        job_id: CloneJobId,
    ) -> Result<CloneJobRecord, ControlPlaneError> {
        self.repository.cancel_job(job_id).await
    }

    pub async fn retry_job(&self, job_id: CloneJobId) -> Result<CloneJobRecord, ControlPlaneError> {
        self.repository.retry_job(job_id).await
    }

    pub async fn claim_next_job(
        &self,
        daemon_id: &DaemonId,
        lease_ttl_secs: i64,
    ) -> Result<Option<CloneJobRecord>, ControlPlaneError> {
        self.repository
            .claim_next_job(daemon_id, lease_ttl_secs)
            .await
    }

    pub async fn heartbeat_lease(
        &self,
        job_id: CloneJobId,
        lease_token: LeaseToken,
        lease_ttl_secs: i64,
    ) -> Result<bool, ControlPlaneError> {
        self.repository
            .heartbeat_lease(job_id, lease_token, lease_ttl_secs)
            .await
    }

    pub async fn set_phase_and_status(
        &self,
        job_id: CloneJobId,
        lease_token: LeaseToken,
        status: CloneJobStatus,
        phase: CloneJobPhase,
    ) -> Result<CloneJobRecord, ControlPlaneError> {
        self.repository
            .set_phase_and_status(job_id, lease_token, status, phase)
            .await
    }

    pub async fn append_event(
        &self,
        job_id: CloneJobId,
        daemon_id: Option<&DaemonId>,
        phase: CloneJobPhase,
        level: CloneEventLevel,
        kind: &str,
        message: &str,
        details: Value,
    ) -> Result<(), ControlPlaneError> {
        self.repository
            .append_event(job_id, daemon_id, phase, level, kind, message, details)
            .await
    }

    pub async fn complete_job(
        &self,
        job_id: CloneJobId,
        lease_token: LeaseToken,
        verification_summary: Value,
    ) -> Result<CloneJobRecord, ControlPlaneError> {
        self.repository
            .complete_job(job_id, lease_token, verification_summary)
            .await
    }

    pub async fn fail_job(
        &self,
        job_id: CloneJobId,
        lease_token: LeaseToken,
        failure_status: CloneJobStatus,
        failure_summary: Value,
    ) -> Result<CloneJobRecord, ControlPlaneError> {
        self.repository
            .fail_job(job_id, lease_token, failure_status, failure_summary)
            .await
    }
}
