// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package install

import (
	"context"
	"fmt"

	"helm.sh/helm/v4/pkg/cli"
	"helm.sh/helm/v4/pkg/getter"
	"helm.sh/helm/v4/pkg/release"
	v1release "helm.sh/helm/v4/pkg/release/v1"
	"sigs.k8s.io/yaml"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/cilium/cilium/cilium-cli/defaults"
	"github.com/cilium/cilium/cilium-cli/internal/helm"
	"github.com/cilium/cilium/cilium-cli/k8s"
)

func (k *K8sInstaller) UpgradeWithHelm(ctx context.Context, k8sClient *k8s.Client) error {
	if k.params.ListVersions {
		return k.listVersions()
	}
	if err := k.preinstall(ctx); err != nil {
		return err
	}

	vals, err := k.params.HelmOpts.MergeValues(getter.All(cli.New()))
	if err != nil {
		return err
	}

	upgradeParams := helm.UpgradeParameters{
		Namespace:            k.params.Namespace,
		Name:                 k.params.HelmReleaseName,
		Chart:                k.chart, // k.chart was initialized in NewK8sInstaller, based on Version and HelmChartDirectory
		Values:               vals,
		ResetValues:          k.params.HelmResetValues,
		ReuseValues:          k.params.HelmReuseValues,
		ResetThenReuseValues: k.params.HelmResetThenReuseValues,
		Wait:                 k.params.Wait,
		WaitDuration:         k.params.WaitDuration,
		MaxHistory:           k.params.HelmMaxHistory,

		// In addition to the DryRun i/o, we need to tell Helm not to execute the upgrade
		DryRun:           k.params.DryRun,
		DryRunHelmValues: k.params.DryRunHelmValues,
	}
	rel, err := helm.Upgrade(ctx, k8sClient.HelmActionConfig, upgradeParams)
	if err != nil {
		return err
	}

	if k.params.DryRun {
		accessor, err := release.NewAccessor(rel)
		if err != nil {
			return fmt.Errorf("failed to create release accessor: %w", err)
		}
		fmt.Println(accessor.Manifest())
	}
	if k.params.DryRunHelmValues {
		v1rel, ok := rel.(*v1release.Release)
		if !ok {
			return fmt.Errorf("unsupported release type: %T", rel)
		}
		helmValues, err := yaml.Marshal(v1rel.Config)
		if err != nil {
			return err
		}
		fmt.Println(string(helmValues))
	}
	if !k.params.Restart {
		fmt.Println("⚠️  You maybe need to restart Cilium pods for configmap changes to take effect")
		return nil
	}

	if err := k.client.DeletePodCollection(ctx, k.params.Namespace,
		metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: defaults.AgentPodSelector}); err != nil {
		return fmt.Errorf("⚠️  unable to restart Cilium pods: %w", err)
	}

	if err := k.client.DeletePodCollection(ctx, k.params.Namespace,
		metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: defaults.OperatorPodSelector}); err != nil {
		return fmt.Errorf("⚠️  unable to restart Cilium Operator pods: %w", err)
	}

	fmt.Println("♻️  Force restarted Cilium pods")

	return err
}
