package PVE::Ceph::Releases;

use v5.36;

use PVE::pvecfg;

my sub get_current_pve_major_release {
    my $release_tuples = [split(/\./, PVE::pvecfg::release())];
    return $release_tuples->[0];
}

my $_ceph_release_info;
my sub get_ceph_release_def {
    if (defined($_ceph_release_info)) {
        return $_ceph_release_info;
    }

    # Track all ceph releases (from a initial cut-off) with some metainfo.
    #
    # Schema keys:
    #  - `release`: version number of the stable release, which for ceph normally is `X.2`
    #  - `initial-upstream-release`: the ISO 8601 formatted day when upstream made their initial
    #    stable release.
    #  - `estimated-end-of-upstream-support`: the ISO 8601 formatted day when upstream will go EOL
    #  - `available-for-pve-release`: a hash that denotes for which PVE major release series a ceph
    #    release is available, where available does not necessarily means (already) fully supported
    #  - `current-backend-default`: set to `1` if a release is currently used as default in the
    #    backend, i.e. by pveceph. The wizard from the web UI often uses a newer release, which is
    #    currently tracked manually there.
    #  - `unsupported`: set to `1` to mark a release as (currently) unsupported, which most often
    #    means that upstream either had no stable release yet, or we aren't 100 % finished with QA
    #    of that release yet.
    #
    # NOTE: very old releases got left out from the list, but there's _no_ need to clean-up
    # periodically check https://docs.ceph.com/en/latest/releases/ for all past releases
    my $ceph_release_info = {
        octopus => {
            release => '15.2',
            'initial-upstream-release' => '2020-03-23',
            'estimated-end-of-upstream-support' => '2022-08-09',
            'available-for-pve-release' => {
                6 => 1,
                7 => 1,
            },
        },
        pacific => {
            release => '16.2',
            'initial-upstream-release' => '2021-03-31',
            'estimated-end-of-upstream-support' => '2024-03-04',
            'available-for-pve-release' => {
                7 => 1,
            },
        },
        quincy => {
            release => '17.2',
            'current-backend-default' => 1,
            'initial-upstream-release' => '2022-04-19',
            'estimated-end-of-upstream-support' => '2024-06-01',
            'available-for-pve-release' => {
                7 => 1,
                8 => 1,
            },
        },
        reef => {
            release => '18.2',
            'initial-upstream-release' => '2023-08-07',
            'estimated-end-of-upstream-support' => '2025-08-01',
            'available-for-pve-release' => {
                8 => 1,
            },
        },
        squid => {
            release => '19.2',
            'initial-upstream-release' => '2024-09-27',
            'estimated-end-of-upstream-support' => '2026-09-19',
            'available-for-pve-release' => {
                8 => 1,
            },
        },
    };

    my $current_pve_major_release = get_current_pve_major_release();
    for my $codename (sort keys $ceph_release_info->%*) {
        my $ceph_release = $ceph_release_info->{$codename};
        $ceph_release->{codename} = $codename;
        $ceph_release->{'available-for-current-pve-release'} =
            $ceph_release->{'available-for-pve-release'}->{$current_pve_major_release};
    }

    $_ceph_release_info = $ceph_release_info;
}

sub get_ceph_release_info($codename) {
    my $ceph_releases = get_ceph_release_def();
    return $ceph_releases->{$codename};
}

my $_available_ceph_releases;

sub get_all_available_ceph_releases {
    if (!defined($_available_ceph_releases)) {
        my $ceph_releases = get_ceph_release_def();
        $_available_ceph_releases = {};
        for my $codename (sort keys $ceph_releases->%*) {
            if ($ceph_releases->{$codename}->{'available-for-current-pve-release'}) {
                $_available_ceph_releases->{$codename} = $ceph_releases->{$codename};
            }
        }
    }
    return $_available_ceph_releases;
}

sub get_available_ceph_release_codenames($include_unstable_releases = 0) {
    my $available_releases = get_all_available_ceph_releases();

    return $include_unstable_releases
        ? [sort keys $available_releases->%*]
        : [grep { !$available_releases->{$_}->{unsupported} } sort keys $available_releases->%*];
}

my $_default_ceph_release_codename;

sub get_default_ceph_release_codename {
    if (!defined($_default_ceph_release_codename)) {
        my $ceph_releases = get_all_available_ceph_releases();
        my @default_release =
            grep { $ceph_releases->{$_}->{'current-backend-default'} } keys $ceph_releases->%*;
        die "internal error: got multiple ceph releases with 'current-backend-default' set\n"
            if scalar(@default_release) > 1;
        die "internal error: got no ceph releases with 'current-backend-default' set\n"
            if scalar(@default_release) < 1;
        $_default_ceph_release_codename = $default_release[0];
    }
    return $_default_ceph_release_codename;
}

1;
