// rust-style-allow: large-file - registry wire/domain types are kept together so
// local, hosted, install, publish, trust, and signed-manifest envelopes evolve
// under one serialization contract.
use runx_contracts::JsonValue;
use runx_contracts::maturity::MaturityTier;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistryLinkResolution {
    pub link: String,
    pub skill_id: String,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub registry_url: Option<String>,
    pub install_command: String,
    pub run_command: String,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TrustTier {
    FirstParty,
    Verified,
    Community,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ProfileMode {
    Portable,
    Profiled,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistryPublisher {
    pub kind: String,
    pub id: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub handle: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub display_name: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistryManifestSigner {
    pub id: String,
    pub key_id: String,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistryManifestSignature {
    pub alg: String,
    pub value: String,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistrySignedManifest {
    pub schema: String,
    pub skill_id: String,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub package_digest: Option<String>,
    pub signer: RegistryManifestSigner,
    pub signature: RegistryManifestSignature,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistryPackageFile {
    pub path: String,
    pub content: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistryAttestation {
    pub kind: String,
    pub id: String,
    pub status: String,
    pub summary: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub issued_at: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub metadata: Option<JsonValue>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistrySourceMetadata {
    pub provider: String,
    pub repo: String,
    pub repo_url: String,
    pub skill_path: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_path: Option<String>,
    pub r#ref: String,
    pub sha: String,
    pub default_branch: String,
    pub event: String,
    pub immutable: bool,
    pub live: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tombstoned: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tag: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub publisher_handle: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TrustSignal {
    pub id: String,
    pub label: String,
    pub status: String,
    pub value: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistrySearchResult {
    pub skill_id: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub summary: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_category: Option<String>,
    pub owner: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub digest: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_label: Option<String>,
    pub source_type: String,
    pub profile_mode: ProfileMode,
    pub runner_names: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_trust_tier: Option<TrustTier>,
    pub required_scopes: Vec<String>,
    pub tags: Vec<String>,
    pub trust_tier: TrustTier,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub trust_signals: Vec<TrustSignal>,
    pub install_command: String,
    pub run_command: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistrySkillVersion {
    pub skill_id: String,
    pub owner: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_category: Option<String>,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub signed_manifest: Option<RegistrySignedManifest>,
    pub markdown: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_document: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub package_files: Vec<RegistryPackageFile>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub package_digest: Option<String>,
    pub runner_names: Vec<String>,
    pub source_type: String,
    pub trust_tier: TrustTier,
    #[serde(default)]
    pub maturity: MaturityTier,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub catalog_kind: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub catalog_audience: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub catalog_visibility: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_metadata: Option<RegistrySourceMetadata>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub attestations: Vec<RegistryAttestation>,
    pub required_scopes: Vec<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub runtime: Option<JsonValue>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub auth: Option<JsonValue>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub risk: Option<JsonValue>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub runx: Option<runx_contracts::JsonObject>,
    pub tags: Vec<String>,
    pub publisher: RegistryPublisher,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistrySkill {
    pub skill_id: String,
    pub owner: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_category: Option<String>,
    pub latest_version: String,
    pub latest_digest: String,
    pub versions: Vec<RegistrySkillVersion>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistrySkillResolution {
    pub markdown: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_document: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub package_files: Vec<RegistryPackageFile>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub package_digest: Option<String>,
    pub runner_names: Vec<String>,
    pub skill_id: String,
    pub name: String,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub signed_manifest: Option<RegistrySignedManifest>,
    pub source: String,
    pub source_label: String,
    pub source_type: String,
    pub trust_tier: TrustTier,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub registry_url: Option<String>,
    pub install_command: String,
    pub run_command: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PublishSkillMarkdownResult {
    pub status: PublishStatus,
    pub skill_id: String,
    pub name: String,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub signed_manifest: Option<RegistrySignedManifest>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    pub runner_names: Vec<String>,
    pub source_type: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub registry_url: Option<String>,
    #[serde(default)]
    pub harness: RegistryPublishHarnessReport,
    pub link: RegistryLinkResolution,
    pub record: RegistrySkillVersion,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RegistryPublishHarnessReport {
    pub status: String,
    pub case_count: usize,
    pub assertion_error_count: usize,
    pub assertion_errors: Vec<String>,
    pub case_names: Vec<String>,
    pub receipt_ids: Vec<String>,
    pub graph_case_count: usize,
}

impl RegistryPublishHarnessReport {
    #[must_use]
    pub fn not_declared() -> Self {
        Self {
            status: "not_declared".to_owned(),
            case_count: 0,
            assertion_error_count: 0,
            assertion_errors: Vec::new(),
            case_names: Vec::new(),
            receipt_ids: Vec::new(),
            graph_case_count: 0,
        }
    }

    #[must_use]
    pub fn failed(&self) -> bool {
        self.status == "failed"
    }
}

impl Default for RegistryPublishHarnessReport {
    fn default() -> Self {
        Self::not_declared()
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PublishStatus {
    Published,
    Unchanged,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegistrySkillDetail {
    pub skill_id: String,
    pub owner: String,
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_category: Option<String>,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub signed_manifest: Option<RegistrySignedManifest>,
    pub markdown: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub package_files: Vec<RegistryPackageFile>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub package_digest: Option<String>,
    pub runner_names: Vec<String>,
    pub source_type: String,
    pub trust_tier: TrustTier,
    pub required_scopes: Vec<String>,
    pub tags: Vec<String>,
    pub publisher: RegistryPublisher,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_metadata: Option<RegistrySourceMetadata>,
    pub attestations: Vec<RegistryAttestation>,
    pub install_command: String,
    pub run_command: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct AcquiredRegistrySkill {
    pub skill_id: String,
    pub owner: String,
    pub name: String,
    pub version: String,
    pub digest: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub signed_manifest: Option<RegistrySignedManifest>,
    pub markdown: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_document: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_digest: Option<String>,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub package_files: Vec<RegistryPackageFile>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub package_digest: Option<String>,
    pub runner_names: Vec<String>,
    pub trust_tier: TrustTier,
    pub publisher: RegistryPublisher,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_metadata: Option<RegistrySourceMetadata>,
    pub attestations: Vec<RegistryAttestation>,
    pub install_count: u64,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct ResolvedRegistryRef {
    pub skill_id: String,
    pub version: Option<String>,
}
