# Extension Publishing to Gitea
#
# Publish extensions as Gitea releases with packaged artifacts
#
# Version: 1.0.0

# Selective imports (ADR-025 Phase 3 Layer 2).
use lib_provisioning/gitea/api_client.nu [
    create-release create-repository get-gitea-config get-gitea-token
    get-release-by-tag get-repository list-releases upload-release-asset
]
use lib_provisioning/config/loader.nu [get-config]

# Validate extension structure
def validate-extension [
    extension_path: string
] -> record {
    let ext_path = $extension_path | path expand

    if not ($ext_path | path exists) {
        error make {
            msg: $"Extension path does not exist: ($ext_path)"
        }
    }

    # Check for required files
    let has_nickel_mod = $"($ext_path)/nickel/nickel.mod" | path exists
    let has_main_file = (
        ls $"($ext_path)/nickel/*.ncl" | where name !~ ".*test.*" | length
    ) > 0

    if not $has_nickel_mod {
        error make {
            msg: "Extension missing nickel/nickel.mod"
        }
    }

    if not $has_main_file {
        error make {
            msg: "Extension missing main Nickel file"
        }
    }

    # Get extension type from path
    let path_parts = $ext_path | split row "/"
    let ext_type = if ($path_parts | any {|p| $p == "providers"}) {
        "provider"
    } else if ($path_parts | any {|p| $p == "taskservs"}) {
        "taskserv"
    } else if ($path_parts | any {|p| $p == "clusters"}) {
        "cluster"
    } else {
        "unknown"
    }

    # Get extension name
    let ext_name = $ext_path | path basename

    {
        valid: true
        extension_type: $ext_type
        extension_name: $ext_name
        path: $ext_path
    }
}

# Package extension
def package-extension [
    extension_path: string
    version: string
    output_dir: string
] -> string {
    let ext_path = $extension_path | path expand
    let ext_name = $ext_path | path basename
    let out_dir = $output_dir | path expand

    mkdir $out_dir

    let archive_name = $"($ext_name)-($version).tar.gz"
    let archive_path = $"($out_dir)/($archive_name)"

    # Create tar archive
    cd ($ext_path | path dirname)
    ^tar czf $archive_path $ext_name

    print $"✓ Packaged extension: ($archive_path)"
    $archive_path
}

# Generate release notes from CHANGELOG
def generate-release-notes [
    extension_path: string
    version: string
] -> string {
    let changelog_path = $"($extension_path)/CHANGELOG.md"

    if not ($changelog_path | path exists) {
        return $"Release ($version)"
    }

    # Try to extract version section from CHANGELOG
    let changelog = open $changelog_path

    # Simple extraction: look for version header
    let version_section = $changelog | lines | reduce -f {found: false, lines: []} {|line, acc|
        if ($line | str contains $"## ($version)") {
            {found: true, lines: []}
        } else if $acc.found and ($line | str starts-with "## ") {
            # Next version found, stop
            $acc
        } else if $acc.found {
            {found: true, lines: ($acc.lines | append $line)}
        } else {
            $acc
        }
    }

    if ($version_section.lines | length) > 0 {
        $version_section.lines | str join "\n" | str trim
    } else {
        $"Release ($version)"
    }
}

# Publish extension to Gitea releases
export def publish-extension-to-gitea [
    extension_path: string
    version: string
    --release-notes: string = ""
    --draft: bool = false
    --prerelease: bool = false
    --output-dir: string = "/tmp/provisioning-extensions"
] -> record {
    # Validate extension
    let validation = validate-extension $extension_path
    print $"✓ Extension validated: ($validation.extension_name) (($validation.extension_type))"

    # Get Gitea config
    let config = get-gitea-config
    let org = $config.repositories.organization
    let repo = $config.repositories.extensions_repo

    # Ensure extensions repository exists
    let result = (do {
        get-repository $org $repo
    } | complete)

    if $result.exit_code != 0 {
        print $"Creating extensions repository: ($org)/($repo)"
        create-repository $org $repo "Provisioning extensions" false
    }

    # Package extension
    let archive_path = package-extension $extension_path $version $output_dir

    # Generate release notes
    let notes = if ($release_notes | is-empty) {
        generate-release-notes $extension_path $version
    } else {
        $release_notes
    }

    # Create git tag (if extension has git repo)
    let git_dir = $"($extension_path)/.git"
    if ($git_dir | path exists) {
        cd $extension_path
        let tag_result = (do {
            ^git tag -a $"($validation.extension_name)-($version)" -m $"Release ($version)"
            ^git push --tags
        } | complete)

        if $tag_result.exit_code == 0 {
            print $"✓ Git tag created: ($validation.extension_name)-($version)"
        } else {
            print $"⚠️  Could not create git tag (may already exist)"
        }
    }

    # Create Gitea release
    let tag_name = $"($validation.extension_name)-($version)"
    let release_name = $"($validation.extension_name) ($version)"

    let release = create-release $org $repo $tag_name $release_name $notes $draft $prerelease
    print $"✓ Release created: ($release.tag_name)"

    # Upload package as release asset
    upload-release-asset $org $repo $release.id $archive_path
    print $"✓ Asset uploaded: ($archive_path | path basename)"

    # Generate metadata file
    let metadata = {
        extension_name: $validation.extension_name
        extension_type: $validation.extension_type
        version: $version
        release_id: $release.id
        tag_name: $tag_name
        published_at: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
        archive_name: ($archive_path | path basename)
        release_url: $release.html_url
    }

    let metadata_path = $"($output_dir)/($validation.extension_name)-($version)-metadata.json"
    $metadata | save -f $metadata_path

    print $"✓ Extension published successfully!"
    print $"   Release URL: ($release.html_url)"

    $metadata
}

# List published extensions
export def list-gitea-extensions [
    --extension-type: string = ""
] -> list {
    let config = get-gitea-config
    let org = $config.repositories.organization
    let repo = $config.repositories.extensions_repo

    # Get all releases
    let releases = list-releases $org $repo

    $releases | each {|release|
        # Parse extension name and version from tag
        let tag_parts = $release.tag_name | split row "-"
        let ext_name = $tag_parts | first ($tag_parts | length | $in - 1) | str join "-"
        let ext_version = $tag_parts | last

        # Determine extension type from name
        let ext_type = if ($ext_name | str ends-with "_prov") {
            "provider"
        } else if ($ext_name | str starts-with "cluster_") {
            "cluster"
        } else {
            "taskserv"
        }

        {
            extension_name: $ext_name
            extension_type: $ext_type
            version: $ext_version
            tag_name: $release.tag_name
            release_name: $release.name
            published_at: $release.published_at
            draft: $release.draft
            prerelease: $release.prerelease
            url: $release.html_url
            assets: ($release.assets | length)
        }
    }
    | if ($extension_type | is-empty) {
        $in
    } else {
        filter {|ext| $ext.extension_type == $extension_type}
    }
    | sort-by published_at --reverse
}

# Download extension from Gitea release
export def download-gitea-extension [
    extension_name: string
    version: string
    destination: string
] -> bool {
    let config = get-gitea-config
    let token = get-gitea-token $config
    let org = $config.repositories.organization
    let repo = $config.repositories.extensions_repo

    # Get release
    let tag_name = $"($extension_name)-($version)"
    let release = get-release-by-tag $org $repo $tag_name

    # Find asset
    let archive_name = $"($extension_name)-($version).tar.gz"
    let asset = $release.assets | where name == $archive_name | first

    if ($asset | is-empty) {
        error make {
            msg: $"Asset not found: ($archive_name)"
        }
    }

    # Download asset
    let download_url = $asset.browser_download_url
    let dest_path = $"($destination)/($archive_name)" | path expand

    mkdir ($destination | path expand)

    # Download with authorization
    ^curl -L -H $"Authorization: token ($token)" -o $dest_path $download_url

    print $"✓ Downloaded: ($dest_path)"

    # Extract archive
    cd ($destination | path expand)
    ^tar xzf $archive_name

    print $"✓ Extracted: ($extension_name)"

    true
}

# Get extension metadata from Gitea
export def get-gitea-extension-metadata [
    extension_name: string
    version: string
] -> record {
    let config = get-gitea-config
    let org = $config.repositories.organization
    let repo = $config.repositories.extensions_repo

    # Get release
    let tag_name = $"($extension_name)-($version)"
    let release = get-release-by-tag $org $repo $tag_name

    # Determine extension type
    let ext_type = if ($extension_name | str ends-with "_prov") {
        "provider"
    } else if ($extension_name | str starts-with "cluster_") {
        "cluster"
    } else {
        "taskserv"
    }

    {
        extension_name: $extension_name
        extension_type: $ext_type
        version: $version
        tag_name: $release.tag_name
        release_name: $release.name
        body: $release.body
        published_at: $release.published_at
        draft: $release.draft
        prerelease: $release.prerelease
        url: $release.html_url
        assets: $release.assets
    }
}

# Get latest version of extension
export def get-latest-extension-version [
    extension_name: string
] -> string {
    let extensions = list-gitea-extensions
    let matching = $extensions | where extension_name == $extension_name

    if ($matching | length) == 0 {
        error make {
            msg: $"Extension not found: ($extension_name)"
        }
    }

    ($matching | first).version
}

# Publish multiple extensions
export def publish-extensions-batch [
    extensions_dir: string
    version: string
    --extension-type: string = ""
] -> list {
    let extensions_path = $extensions_dir | path expand

    # Find all extensions
    let extensions = if ($extension_type | is-empty) {
        ls $extensions_path | where type == dir
    } else {
        ls $"($extensions_path)/($extension_type)s" | where type == dir
    }

    $extensions | each {|ext|
        print $"Publishing ($ext.name)..."
        let result = (do {
            publish-extension-to-gitea $ext.name $version
        } | complete)

        if $result.exit_code == 0 {
            $result.stdout
        } else {
            print $"❌ Failed to publish ($ext.name): ($result.stderr)"
            null
        }
    } | where {|x| $x != null}
}
