//! Core extension registry service implementation

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

use anyhow::Result;
use serde::{Deserialize, Serialize};
use sha2::Digest;
use tokio::sync::RwLock;

/// OCI image manifest
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageManifest {
    /// Schema version
    pub schema_version: u32,
    /// Media type
    pub media_type: String,
    /// Image config digest (sha256:...)
    pub config: ManifestConfig,
    /// Image layers
    pub layers: Vec<Layer>,
}

/// Image configuration reference
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManifestConfig {
    /// Digest (sha256:...)
    pub digest: String,
    /// Size in bytes
    pub size: u64,
    /// Media type
    pub media_type: String,
}

/// Image layer
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Layer {
    /// Layer digest (sha256:...)
    pub digest: String,
    /// Size in bytes
    pub size: u64,
    /// Media type
    pub media_type: String,
}

/// Push blob request
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PushBlobRequest {
    /// Blob content
    pub content: Vec<u8>,
    /// Content digest for validation
    pub digest: String,
}

/// Push blob response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PushBlobResponse {
    /// Blob digest
    pub digest: String,
    /// Blob size in bytes
    pub size: u64,
}

/// Pull manifest response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PullManifestResponse {
    /// Image manifest
    pub manifest: ImageManifest,
    /// Manifest digest
    pub digest: String,
    /// Content type
    pub content_type: String,
}

/// Extension metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExtensionMetadata {
    /// Extension name
    pub name: String,
    /// Extension version
    pub version: String,
    /// Extension description
    pub description: String,
    /// Supported platforms (e.g., ["linux/amd64", "linux/arm64"])
    pub platforms: Vec<String>,
}

/// Core extension registry service
pub struct ExtensionRegistry {
    /// Server address
    addr: SocketAddr,
    /// Stored blobs (digest -> content)
    blobs: Arc<RwLock<HashMap<String, Vec<u8>>>>,
    /// Stored manifests (repo:tag -> manifest)
    manifests: Arc<RwLock<HashMap<String, ImageManifest>>>,
    /// Extension metadata registry
    extensions: Arc<RwLock<HashMap<String, ExtensionMetadata>>>,
}

impl ExtensionRegistry {
    /// Create new extension registry
    pub fn new(addr: SocketAddr) -> Self {
        Self {
            addr,
            blobs: Arc::new(RwLock::new(HashMap::new())),
            manifests: Arc::new(RwLock::new(HashMap::new())),
            extensions: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    /// Get service address
    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    /// Check if blob exists
    pub async fn blob_exists(&self, digest: &str) -> Result<bool> {
        let blobs = self.blobs.read().await;
        Ok(blobs.contains_key(digest))
    }

    /// Push blob to registry
    pub async fn push_blob(&self, req: PushBlobRequest) -> Result<PushBlobResponse> {
        let size = req.content.len() as u64;
        let mut blobs = self.blobs.write().await;
        blobs.insert(req.digest.clone(), req.content);

        Ok(PushBlobResponse {
            digest: req.digest,
            size,
        })
    }

    /// Pull blob from registry
    pub async fn pull_blob(&self, digest: &str) -> Result<Vec<u8>> {
        let blobs = self.blobs.read().await;
        blobs
            .get(digest)
            .cloned()
            .ok_or_else(|| anyhow::anyhow!("Blob not found: {}", digest))
    }

    /// Check if manifest exists
    pub async fn manifest_exists(&self, reference: &str) -> Result<bool> {
        let manifests = self.manifests.read().await;
        Ok(manifests.contains_key(reference))
    }

    /// Put image manifest
    pub async fn put_manifest(&self, reference: String, manifest: ImageManifest) -> Result<String> {
        let digest = format!(
            "sha256:{}",
            hex::encode(sha2::Sha256::digest(&serde_json::to_vec(&manifest)?))
        );

        let mut manifests = self.manifests.write().await;
        manifests.insert(reference, manifest);

        Ok(digest)
    }

    /// Get image manifest
    pub async fn get_manifest(&self, reference: &str) -> Result<PullManifestResponse> {
        let manifests = self.manifests.read().await;
        let manifest = manifests
            .get(reference)
            .cloned()
            .ok_or_else(|| anyhow::anyhow!("Manifest not found: {}", reference))?;

        let digest = format!(
            "sha256:{}",
            hex::encode(sha2::Sha256::digest(&serde_json::to_vec(&manifest)?))
        );

        Ok(PullManifestResponse {
            manifest,
            digest,
            content_type: "application/vnd.docker.distribution.manifest.v2+json".to_string(),
        })
    }

    /// Register extension
    pub async fn register_extension(&self, metadata: ExtensionMetadata) -> Result<()> {
        let mut extensions = self.extensions.write().await;
        extensions.insert(metadata.name.clone(), metadata);
        Ok(())
    }

    /// Get extension metadata
    pub async fn get_extension(&self, name: &str) -> Result<ExtensionMetadata> {
        let extensions = self.extensions.read().await;
        extensions
            .get(name)
            .cloned()
            .ok_or_else(|| anyhow::anyhow!("Extension not found: {}", name))
    }

    /// List all extensions
    pub async fn list_extensions(&self) -> Result<Vec<ExtensionMetadata>> {
        let extensions = self.extensions.read().await;
        Ok(extensions.values().cloned().collect())
    }

    /// Health check endpoint
    pub async fn health_check(&self) -> Result<()> {
        Ok(())
    }
}

impl Default for ExtensionRegistry {
    fn default() -> Self {
        Self::new("127.0.0.1:8084".parse().unwrap())
    }
}
