/*
Copyright 2026 The Flux authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"fmt"

	"github.com/spf13/cobra"
	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/yaml"

	notificationv1 "github.com/fluxcd/notification-controller/api/v1"

	"github.com/fluxcd/flux2/v2/internal/flags"
	"github.com/fluxcd/flux2/v2/internal/utils"
	"github.com/fluxcd/flux2/v2/pkg/manifestgen/sourcesecret"
)

var createSecretReceiverCmd = &cobra.Command{
	Use:   "receiver [name]",
	Short: "Create or update a Kubernetes secret for a Receiver webhook",
	Long: `The create secret receiver command generates a Kubernetes secret with
the token used for webhook payload validation and an annotation with the
computed webhook URL.`,
	Example: `  # Create a receiver secret for a GitHub webhook
  flux create secret receiver github-receiver \
    --namespace=my-namespace \
    --type=github \
    --hostname=flux.example.com \
    --export

  # Create a receiver secret for GCR with email claim
  flux create secret receiver gcr-receiver \
    --namespace=my-namespace \
    --type=gcr \
    --hostname=flux.example.com \
    --email-claim=sa@project.iam.gserviceaccount.com \
    --export`,
	RunE: createSecretReceiverCmdRun,
}

type secretReceiverFlags struct {
	receiverType  flags.ReceiverType
	token         string
	hostname      string
	emailClaim    string
	audienceClaim string
}

var secretReceiverArgs secretReceiverFlags

func init() {
	createSecretReceiverCmd.Flags().Var(&secretReceiverArgs.receiverType, "type", secretReceiverArgs.receiverType.Description())
	createSecretReceiverCmd.Flags().StringVar(&secretReceiverArgs.token, "token", "", "webhook token used for payload validation and URL computation, auto-generated if not specified")
	createSecretReceiverCmd.Flags().StringVar(&secretReceiverArgs.hostname, "hostname", "", "hostname for the webhook URL e.g. flux.example.com")
	createSecretReceiverCmd.Flags().StringVar(&secretReceiverArgs.emailClaim, "email-claim", "", "IAM service account email, required for gcr type")
	createSecretReceiverCmd.Flags().StringVar(&secretReceiverArgs.audienceClaim, "audience-claim", "", "custom OIDC token audience for gcr type, defaults to the webhook URL")

	createSecretCmd.AddCommand(createSecretReceiverCmd)
}

func createSecretReceiverCmdRun(cmd *cobra.Command, args []string) error {
	name := args[0]

	if secretReceiverArgs.receiverType == "" {
		return fmt.Errorf("--type is required")
	}

	if secretReceiverArgs.hostname == "" {
		return fmt.Errorf("--hostname is required")
	}

	if secretReceiverArgs.receiverType.String() == notificationv1.GCRReceiver && secretReceiverArgs.emailClaim == "" {
		return fmt.Errorf("--email-claim is required for gcr receiver type")
	}

	labels, err := parseLabels()
	if err != nil {
		return err
	}

	opts := sourcesecret.Options{
		Name:          name,
		Namespace:     *kubeconfigArgs.Namespace,
		Labels:        labels,
		ReceiverType:  secretReceiverArgs.receiverType.String(),
		Token:         secretReceiverArgs.token,
		Hostname:      secretReceiverArgs.hostname,
		EmailClaim:    secretReceiverArgs.emailClaim,
		AudienceClaim: secretReceiverArgs.audienceClaim,
	}

	secret, err := sourcesecret.GenerateReceiver(opts)
	if err != nil {
		return err
	}

	if createArgs.export {
		rootCmd.Println(secret.Content)
		return nil
	}

	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
	defer cancel()
	kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
	if err != nil {
		return err
	}
	var s corev1.Secret
	if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
		return err
	}
	if err := upsertSecret(ctx, kubeClient, s); err != nil {
		return err
	}

	logger.Actionf("receiver secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
	return nil
}
