// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package auth

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/opentofu/opentofu/internal/httpclient"
	"github.com/opentofu/opentofu/internal/tfdiags"
)

type ClientSecretCredentialAuthConfig struct {
	ClientID             string
	ClientIDFilePath     string
	ClientSecret         string
	ClientSecretFilePath string
}

type clientSecretCredentialAuth struct{}

var _ AuthMethod = &clientSecretCredentialAuth{}

func (cred *clientSecretCredentialAuth) Name() string {
	return "Client Secret Auth"
}

func (cred *clientSecretCredentialAuth) Construct(ctx context.Context, config *Config) (azcore.TokenCredential, error) {
	client := httpclient.New(ctx)
	clientId, err := consolidateClientId(config)
	if err != nil {
		// This should never happen; this is checked in the Validate function
		return nil, err
	}
	clientSecret, err := consolidateClientSecret(config)
	if err != nil {
		// This should never happen; this is checked in the Validate function
		return nil, err
	}

	return azidentity.NewClientSecretCredential(
		config.StorageAddresses.TenantID,
		clientId,
		clientSecret,
		&azidentity.ClientSecretCredentialOptions{
			ClientOptions: clientOptions(client, config.CloudConfig),
		},
	)
}

func (cred *clientSecretCredentialAuth) Validate(_ context.Context, config *Config) tfdiags.Diagnostics {
	var diags tfdiags.Diagnostics
	if config.StorageAddresses.TenantID == "" {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Invalid Azure Client Secret Auth",
			"Tenant ID is missing.",
		))
	}
	_, err := consolidateClientId(config)
	if err != nil {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Invalid Azure Client Secret Auth",
			fmt.Sprintf("The Client ID is misconfigured: %s.", tfdiags.FormatError(err)),
		))
	}
	_, err = consolidateClientSecret(config)
	if err != nil {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Invalid Azure Client Secret Auth",
			fmt.Sprintf("The Client Secret is misconfigured: %s.", tfdiags.FormatError(err)),
		))
	}
	return diags
}

func (cred *clientSecretCredentialAuth) AugmentConfig(_ context.Context, config *Config) error {
	return checkNamesForAccessKeyCredentials(config.StorageAddresses)
}

func consolidateClientId(config *Config) (string, error) {
	return consolidateFileAndValue(config.ClientID, config.ClientIDFilePath, "client ID", false)
}

func consolidateClientSecret(config *Config) (string, error) {
	return consolidateFileAndValue(config.ClientSecret, config.ClientSecretFilePath, "client secret", false)
}
