# Module: Extension Discovery System
# Purpose: Discovers and loads available extensions from filesystem and Gitea (deferred v2.1).
# Dependencies: loader for configuration

# Extension Discovery and Search
# Discovers extensions across OCI registries, Gitea, and local sources

# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/utils/logging.nu [log-debug log-error log-info]
use lib_provisioning/oci/client.nu [
    get-oci-config is-oci-available load-oci-token oci-get-artifact-manifest
    oci-get-artifact-tags oci-list-artifacts
]
use lib_provisioning/extensions/versions.nu [is-semver sort-by-semver get-latest-version]

# Discover extensions in OCI registry
export def discover-oci-extensions [
    oci_config?: record
    extension_type?: string
] {
    let result = (do {
        let config = if ($oci_config | is-empty) {
            get-oci-config
        } else {
            $oci_config
        }

        let token = (load-oci-token $config.auth_token_path)

        log-info $"Discovering extensions in OCI registry: ($config.registry)/($config.namespace)"

        # List all artifacts
        let artifacts = (oci-list-artifacts $config.registry $config.namespace --auth-token $token)

        if ($artifacts | is-empty) {
            log-warn "No artifacts found in OCI registry"
            return []
        }

        # Get metadata for each artifact
        let extensions = ($artifacts | each {|artifact_name|
            let item_result = (do {
                let tags = (oci-get-artifact-tags $config.registry $config.namespace $artifact_name --auth-token $token)

                if ($tags | is-empty) {
                    null
                } else {
                    let semver_tags = ($tags | where ($it | is-semver))
                    let latest = if ($semver_tags | is-not-empty) {
                        $semver_tags | sort-by-semver | last
                    } else {
                        $tags | last
                    }

                    # Get manifest for latest version
                    let manifest = (oci-get-artifact-manifest
                        $config.registry
                        $config.namespace
                        $artifact_name
                        $latest
                        --auth-token $token
                    )

                    # Extract extension type from annotations
                    let ext_type = (extract-extension-type $manifest)

                    {
                        name: $artifact_name
                        type: $ext_type
                        versions: $tags
                        latest: $latest
                        source: "oci"
                        registry: $config.registry
                        namespace: $config.namespace
                        digest: ($manifest.config?.digest? | default "")
                        annotations: ($manifest.config?.annotations? | default {})
                    }
                }
            } | complete)

            if $item_result.exit_code == 0 {
                $item_result.stdout
            } else {
                log-warn $"Failed to get metadata for ($artifact_name): ($item_result.stderr)"
                null
            }
        } | compact)

        # Filter by extension type if specified
        if ($extension_type | is-not-empty) {
            $extensions | where type == $extension_type
        } else {
            $extensions
        }
    } | complete)

    if $result.exit_code == 0 {
        $result.stdout
    } else {
        log-error $"Failed to discover OCI extensions: ($result.stderr)"
        []
    }
}

# Search extensions in OCI registry
export def search-oci-extensions [
    query: string
    oci_config?: record
] {
    let result = (do {
        let all_extensions = (discover-oci-extensions $oci_config)

        $all_extensions | where {|ext|
            ($ext.name | str contains $query) or ($ext.type | str contains $query)
        }
    } | complete)

    if $result.exit_code == 0 {
        $result.stdout
    } else {
        log-error $"Failed to search OCI extensions: ($result.stderr)"
        []
    }
}

# Get extension metadata from OCI registry
export def get-oci-extension-metadata [
    extension_name: string
    version: string
    oci_config?: record
] {
    let result = (do {
        let config = if ($oci_config | is-empty) {
            get-oci-config
        } else {
            $oci_config
        }

        let token = (load-oci-token $config.auth_token_path)

        let manifest = (oci-get-artifact-manifest
            $config.registry
            $config.namespace
            $extension_name
            $version
            --auth-token $token
        )

        if ($manifest | is-empty) {
            return {}
        }

        {
            name: $extension_name
            version: $version
            source: "oci"
            registry: $config.registry
            namespace: $config.namespace
            oci_digest: ($manifest.config?.digest? | default "")
            created: ($manifest.config?.created? | default "")
            size: ($manifest.config?.size? | default 0)
            annotations: ($manifest.config?.annotations? | default {})
            layers: ($manifest.layers? | default [])
            media_type: ($manifest.mediaType? | default "")
        }
    } | complete)

    if $result.exit_code == 0 {
        $result.stdout
    } else {
        log-error $"Failed to get OCI extension metadata: ($result.stderr)"
        {}
    }
}

# Discover local extensions
export def discover-local-extensions [
    extension_type?: string
] {
    let extension_paths = [
        ($env.PWD | path join ".provisioning" "extensions")
        ($env.HOME | path join ".provisioning-extensions")
        "/opt/provisioning-extensions"
    ] | where ($it | path exists)

    let extensions = ($extension_paths | each {|base_path|
        discover-in-path $base_path $extension_type
    } | flatten)

    $extensions
}

# Discover extensions in specific path
def discover-in-path [
    base_path: string
    extension_type?: string
] {
    let type_dirs = if ($extension_type | is-not-empty) {
        [$extension_type]
    } else {
        ["providers", "taskservs", "clusters"]
    }

    $type_dirs | each {|type_dir|
        let type_path = ($base_path | path join $type_dir)

        if not ($type_path | path exists) {
            return []
        }

        let extensions = (ls $type_path
            | where type == dir
            | get name
            | each {|ext_path|
                let item_result = (do {
                    let ext_name = ($ext_path | path basename)
                    let manifest_file = ($ext_path | path join "extension.yaml")

                    let manifest = if ($manifest_file | path exists) {
                        open $manifest_file | from yaml
                    } else {
                        {
                            extension: {
                                name: $ext_name
                                type: $type_dir
                                version: "local"
                            }
                        }
                    }

                    {
                        name: ($manifest.extension.name? | default $ext_name)
                        type: ($manifest.extension.type? | default $type_dir)
                        version: ($manifest.extension.version? | default "local")
                        path: $ext_path
                        source: "local"
                        description: ($manifest.extension.description? | default "")
                    }
                } | complete)

                if $item_result.exit_code == 0 {
                    $item_result.stdout
                } else {
                    log-warn $"Failed to read extension at ($ext_path): ($item_result.stderr)"
                    null
                }
            }
            | compact
        )

        $extensions
    } | flatten
}

# Discover all extensions (OCI, Gitea, Local)
export def discover-all-extensions [
    extension_type?: string
    --include-oci
    --include-gitea
    --include-local
] {
    mut all_extensions = []

    # Discover from OCI if flag set or if no flags set (default all)
    if $include_oci or (not $include_oci and not $include_gitea and not $include_local) {
        if (is-oci-available) {
            let oci_exts = if ($extension_type | is-not-empty) {
                discover-oci-extensions {} $extension_type
            } else {
                discover-oci-extensions
            }
            $all_extensions = ($all_extensions | append $oci_exts)
        }
    }

    # Discover from Gitea if flag set or default
    if $include_gitea or (not $include_oci and not $include_gitea and not $include_local) {
        if (is-gitea-available) {
            # TODO: Implement Gitea discovery
            log-debug "Gitea discovery not yet implemented"
        }
    }

    # Discover from local if flag set or default
    if $include_local or (not $include_oci and not $include_gitea and not $include_local) {
        let local_exts = (discover-local-extensions $extension_type)
        $all_extensions = ($all_extensions | append $local_exts)
    }

    $all_extensions
}

# Search all sources for extensions
export def search-extensions [
    query: string
    --source: string = "all"  # all, oci, gitea, local
] {
    match $source {
        "oci" => {
            search-oci-extensions $query
        }
        "gitea" => {
            # TODO: Implement Gitea search
            log-warn "Gitea search not yet implemented"
            []
        }
        "local" => {
            let local_exts = (discover-local-extensions)
            $local_exts | where {|ext|
                ($ext.name | str contains $query) or ($ext.type | str contains $query) or ($ext.description? | default "" | str contains $query)
            }
        }
        "all" => {
            let all = (discover-all-extensions)
            $all | where {|ext|
                ($ext.name | str contains $query) or ($ext.type | str contains $query)
            }
        }
        _ => {
            log-error $"Unknown source: ($source)"
            []
        }
    }
}

# List extensions with detailed information
export def list-extensions [
    --extension-type: string = ""
    --source: string = "all"
    --format: string = "table"  # table, json, yaml
] {
    let extensions = (discover-all-extensions $extension_type)

    let filtered = if $source != "all" {
        $extensions | where source == $source
    } else {
        $extensions
    }

    match $format {
        "json" => ($filtered | to json)
        "yaml" => ($filtered | to yaml)
        "table" => {
            $filtered
            | select name type version source
            | sort-by type name
        }
        _ => $filtered
    }
}

# Get extension versions from all sources
export def get-extension-versions [
    extension_name: string
    --source: string = "all"
] {
    mut versions = []

    # Get from OCI
    if $source == "all" or $source == "oci" {
        if (is-oci-available) {
            let config = (get-oci-config)
            let token = (load-oci-token $config.auth_token_path)

            let oci_tags = (oci-get-artifact-tags
                $config.registry
                $config.namespace
                $extension_name
                --auth-token $token
            )

            let oci_versions = ($oci_tags | each {|tag|
                {version: $tag, source: "oci"}
            })

            $versions = ($versions | append $oci_versions)
        }
    }

    # Get from Gitea
    if $source == "all" or $source == "gitea" {
        # TODO: Implement Gitea versions
    }

    # Get from local
    if $source == "all" or $source == "local" {
        let local_exts = (discover-local-extensions)
        let local_matches = ($local_exts | where name == $extension_name)

        let local_versions = ($local_matches | each {|ext|
            {version: ($ext.version? | default "local"), source: "local"}
        })

        $versions = ($versions | append $local_versions)
    }

    $versions
}

# Extract extension type from OCI manifest annotations
def extract-extension-type [manifest: record] {
    let annotations = ($manifest.config?.annotations? | default {})

    # Try standard annotation
    let ext_type = ($annotations | get "provisioning.extension.type"? | default null)

    if ($ext_type | is-not-empty) {
        return $ext_type
    }

    # Try OCI image labels
    let labels = ($manifest.config?.config?.Labels? | default {})
    let label_type = ($labels | get "provisioning.extension.type"? | default null)

    if ($label_type | is-not-empty) {
        return $label_type
    }

    # Default to unknown
    "unknown"
}

# Check if Gitea is available
def is-gitea-available [] {
    # TODO: Implement Gitea availability check
    false
}
