package utils

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/aws/aws-sdk-go-v2/aws/arn"
)

// AliCloudARN represents a parsed AliCloud ARN
type AliCloudARN struct {
	Service   string
	Region    string
	AccountID string
	Resource  string
}

// GCPKmsKeyName represents a parsed GCP KMS key name
type GCPKmsKeyName struct {
	Project  string
	Location string
	KeyRing  string
	KeyId    string
}

// AzureKeyVaultKey represents a parsed Azure Key Vault key URL
type AzureKeyVaultKey struct {
	VaultName string
	KeyName   string
	Version   string
}

// --- AWS ARN ---

// ParseAWSARN parses an AWS ARN and optionally validates service and resource prefix
// Format: arn:aws:<service>:<region>:<account>:<resource>
func ParseAWSARN(arnStr, expectedService, expectedResourcePrefix string) (arn.ARN, string, error) {
	if arnStr == "" {
		return arn.ARN{}, "", fmt.Errorf("ARN string is empty")
	}

	parsed, err := arn.Parse(arnStr)
	if err != nil {
		return arn.ARN{}, "", fmt.Errorf("invalid AWS ARN format: %w", err)
	}

	if expectedService != "" && parsed.Service != expectedService {
		return arn.ARN{}, "", fmt.Errorf("invalid AWS ARN: service must be '%s', got '%s'", expectedService, parsed.Service)
	}

	resourceId := parsed.Resource
	if expectedResourcePrefix != "" {
		if !strings.HasPrefix(parsed.Resource, expectedResourcePrefix) {
			return arn.ARN{}, "", fmt.Errorf("invalid AWS ARN: resource must start with '%s', got '%s'", expectedResourcePrefix, parsed.Resource)
		}
		resourceId = strings.TrimPrefix(parsed.Resource, expectedResourcePrefix)
		if resourceId == "" {
			return arn.ARN{}, "", fmt.Errorf("invalid AWS ARN: resource id is empty")
		}
	}

	return parsed, resourceId, nil
}

// ParseAWSKmsKeyId extracts the key ID from an AWS KMS ARN
// Format: arn:aws:kms:region:account:key/key-id
func ParseAWSKmsKeyId(arnStr string) (string, error) {
	_, keyId, err := ParseAWSARN(arnStr, "kms", "key/")
	return keyId, err
}

// ValidateAWSRoleARN validates an AWS IAM role ARN
// Format: arn:aws:iam::account:role/role-name
func ValidateAWSRoleARN(arnStr string) error {
	_, _, err := ParseAWSARN(arnStr, "iam", "role/")
	return err
}

// --- AliCloud ARN ---

// ParseAliCloudARN parses an AliCloud ARN and optionally validates service and resource prefix
// Format: acs:<service>:<region>:<account-id>:<resource>
func ParseAliCloudARN(arnStr, expectedService, expectedResourcePrefix string) (*AliCloudARN, string, error) {
	if arnStr == "" {
		return nil, "", fmt.Errorf("ARN string is empty")
	}

	pattern := `^acs:([\w-]+):([\w-]*):(\d+):([\w/-]+)$`
	re := regexp.MustCompile(pattern)
	matches := re.FindStringSubmatch(arnStr)

	if matches == nil {
		return nil, "", fmt.Errorf("invalid AliCloud ARN format: %s", arnStr)
	}

	parsed := &AliCloudARN{
		Service:   matches[1],
		Region:    matches[2],
		AccountID: matches[3],
		Resource:  matches[4],
	}

	if expectedService != "" && parsed.Service != expectedService {
		return nil, "", fmt.Errorf("invalid AliCloud ARN: service must be '%s', got '%s'", expectedService, parsed.Service)
	}

	resourceId := parsed.Resource
	if expectedResourcePrefix != "" {
		if !strings.HasPrefix(parsed.Resource, expectedResourcePrefix) {
			return nil, "", fmt.Errorf("invalid AliCloud ARN: resource must start with '%s', got '%s'", expectedResourcePrefix, parsed.Resource)
		}
		resourceId = strings.TrimPrefix(parsed.Resource, expectedResourcePrefix)
		if resourceId == "" {
			return nil, "", fmt.Errorf("invalid AliCloud ARN: resource id is empty")
		}
	}

	return parsed, resourceId, nil
}

// ValidateAliCloudARN validates the format of an AliCloud ARN string (no service/resource check)
func ValidateAliCloudARN(arnStr string) bool {
	_, _, err := ParseAliCloudARN(arnStr, "", "")
	return err == nil
}

// ParseAliCloudKmsKeyId extracts the key ID from an AliCloud KMS ARN
// Format: acs:kms:region:account:key/key-id
func ParseAliCloudKmsKeyId(arnStr string) (string, error) {
	_, keyId, err := ParseAliCloudARN(arnStr, "kms", "key/")
	return keyId, err
}

// ValidateAliCloudRoleARN validates an AliCloud RAM role ARN
// Format: acs:ram::account:role/role-name
func ValidateAliCloudRoleARN(arnStr string) error {
	_, _, err := ParseAliCloudARN(arnStr, "ram", "role/")
	return err
}

// --- GCP KMS ---

// ParseGCPKmsKeyName parses a GCP KMS key name and extracts components
// Format: projects/{project}/locations/{location}/keyRings/{keyRing}/cryptoKeys/{keyId}
func ParseGCPKmsKeyName(keyName string) (*GCPKmsKeyName, error) {
	if keyName == "" {
		return nil, fmt.Errorf("key name is empty")
	}

	pattern := `^projects/([^/]+)/locations/([^/]+)/keyRings/([^/]+)/cryptoKeys/([^/]+)$`
	re := regexp.MustCompile(pattern)
	matches := re.FindStringSubmatch(keyName)

	if matches == nil {
		return nil, fmt.Errorf("invalid GCP KMS key name format: %s", keyName)
	}

	return &GCPKmsKeyName{
		Project:  matches[1],
		Location: matches[2],
		KeyRing:  matches[3],
		KeyId:    matches[4],
	}, nil
}

// ParseGCPKmsKeyId extracts the key ID from a GCP KMS key name
func ParseGCPKmsKeyId(keyName string) (string, error) {
	parsed, err := ParseGCPKmsKeyName(keyName)
	if err != nil {
		return "", err
	}
	return parsed.KeyId, nil
}

// --- Azure Key Vault ---

// ParseAzureKeyVaultKeyURL parses an Azure Key Vault key URL and extracts components
// Format: https://{vault-name}.vault.azure.net/keys/{key-name}/{version}
func ParseAzureKeyVaultKeyURL(keyUrl string) (*AzureKeyVaultKey, error) {
	if keyUrl == "" {
		return nil, fmt.Errorf("key URL is empty")
	}

	pattern := `^https://([^/]+)\.vault\.azure\.net/keys/([^/]+)(?:/([^/]+))?$`
	re := regexp.MustCompile(pattern)
	matches := re.FindStringSubmatch(keyUrl)

	if matches == nil {
		return nil, fmt.Errorf("invalid Azure Key Vault URL format: %s", keyUrl)
	}

	return &AzureKeyVaultKey{
		VaultName: matches[1],
		KeyName:   matches[2],
		Version:   matches[3],
	}, nil
}

// ParseAzureKeyVaultKeyId extracts the key name from an Azure Key Vault URL
func ParseAzureKeyVaultKeyId(keyUrl string) (string, error) {
	parsed, err := ParseAzureKeyVaultKeyURL(keyUrl)
	if err != nil {
		return "", err
	}
	return parsed.KeyName, nil
}
