// Copyright 2025 Microsoft Corporation
//
// 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 coreapi

import (
	"path"
	"strings"
	"time"

	azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"

	"github.com/Azure/ARO-HCP/internal/api/metadataapi"
)

type OperationRequest string

const (
	OperationRequestCreate OperationRequest = "Create"
	OperationRequestUpdate OperationRequest = "Update"
	OperationRequestDelete OperationRequest = "Delete"

	// These are for POST actions on resources.
	OperationRequestSystemAdminCredentialRequest    OperationRequest = "RequestCredential"
	OperationRequestSystemAdminCredentialRevocation OperationRequest = "RevokeCredentials"
)

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type Operation struct {
	// PartitionKey holds the lowercased subscriptionID.
	CosmosMetadata `json:"cosmosMetadata"`

	// TenantID is the tenant ID of the client that requested the operation
	TenantID string `json:"tenantId,omitempty"`
	// ClientID is the object ID of the client that requested the operation
	ClientID string `json:"clientId,omitempty"`
	// Request is the type of asynchronous operation requested
	Request OperationRequest `json:"request,omitempty"`
	// ExternalID is the Azure resource ID of the cluster or node pool
	ExternalID *azcorearm.ResourceID `json:"externalId,omitempty"`
	// InternalID is the Cluster Service resource identifier in the form of a URL path
	InternalID metadataapi.InternalID `json:"internalId,omitempty"`
	// OperationID is the Azure resource ID of the operation status (may be nil if the
	// operation was implicit, such as deleting a child resource along with the parent)
	OperationID *azcorearm.ResourceID `json:"operationId,omitempty"`
	// ClientRequestID is provided by the "x-ms-client-request-id" request header
	ClientRequestID string `json:"clientRequestId,omitempty"`
	// CorrelationRequstID is provided by the "x-ms-correlation-request-id" request header
	CorrelationRequestID string `json:"correlationRequestId,omitempty"`
	// NotificationURI is provided by the Azure-AsyncNotificationUri header if the
	// Async Operation Callbacks ARM feature is enabled
	NotificationURI string `json:"notificationUri,omitempty"`

	// StartTime marks the start of the operation
	StartTime time.Time `json:"startTime,omitempty"`
	// LastTransitionTime marks the most recent state change
	LastTransitionTime time.Time `json:"lastTransitionTime,omitempty"`
	// Status is the current operation status, using the same set of values
	// as the resource's provisioning state
	Status ProvisioningState `json:"status,omitempty"`
	// Error is an OData error, present when Status is "Failed" or "Canceled"
	Error *CloudErrorBody `json:"error,omitempty"`

	// Temporary field to track whether the node pool operation is using the new deletion approach.
	// We are migrating from the node pool cs deletion synchronous in frontend to the backend, to be fully asynchronous
	// This boolean is true for NodePool delete operations that are created with new deletion approach.
	// This will be removed once all nodepools whose deletion was triggered before the new approach is fully rolled out have been
	// fully deleted in all ARO-HCP permanent environments, for all regions.
	UsesNewNodePoolDeletionApproach bool `json:"usesNewNodePoolDeletionApproach"`

	// TODO Temporary field to track whether the external auth operation is using the new deletion approach.
	// We are migrating from the external auth CS deletion synchronous in frontend to the backend, to be fully asynchronous.
	// This boolean is true for ExternalAuth delete operations that are created with new deletion approach.
	// This will be removed once all external auths whose deletion was triggered before the new approach is fully rolled out have been
	// fully deleted in all ARO-HCP permanent environments, for all regions.
	UsesNewExternalAuthDeletionApproach bool `json:"usesNewExternalAuthDeletionApproach"`

	// TODO Temporary field to track whether the cluster operation is using the new deletion approach.
	// We are migrating from the cluster CS deletion synchronous in frontend to the backend, to be fully asynchronous.
	// This boolean is true for Cluster delete operations that are created with new deletion approach.
	// This will be removed once all clusters whose deletion was triggered before the new approach is fully rolled out have been
	// fully deleted in all ARO-HCP permanent environments, for all regions.
	UsesNewClusterDeletionApproach bool `json:"usesNewClusterDeletionApproach"`

	// Written by: Frontend POST requestAdminCredential, backend systemadmincredentialcontrollers
	SystemAdminCredentialRequest *OperationSystemAdminCredentialRequest `json:"systemAdminCredentialRequest,omitempty"`
	// Written by: Frontend POST revokeCredentials, backend systemadmincredentialcontrollers
	SystemAdminCredentialRevocation *OperationSystemAdminCredentialRevocation `json:"systemAdminCredentialRevocation,omitempty"`
}

// OperationSystemAdminCredentialRequest groups state for the admin credential
// request lifecycle on an Operation document.
type OperationSystemAdminCredentialRequest struct {
	CertificateSigningRequest              string                `json:"certificateSigningRequest,omitempty"`
	SystemAdminCredentialRequestResourceID *azcorearm.ResourceID `json:"systemAdminCredentialRequestResourceID,omitempty"`
}

// OperationSystemAdminCredentialRevocation groups state for the admin credential
// revocation lifecycle on an Operation document.
type OperationSystemAdminCredentialRevocation struct {
	SystemAdminCredentialRevocationResourceID *azcorearm.ResourceID `json:"systemAdminCredentialRevocationResourceID,omitempty"`
}

func (o *Operation) ComputeLogicalResourceID() *azcorearm.ResourceID {
	return metadataapi.Must(azcorearm.ParseResourceID(
		strings.ToLower(
			path.Join(
				"/subscriptions",
				o.OperationID.SubscriptionID,
				"providers",
				OperationStatusResourceType.String(),
				o.OperationID.Name,
			))))
}
