//nolint:gocritic // Prerequisite validation deliberately receives the immutable activation contract by value.
package byoc

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

	awssdk "github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/iam"
)

const (
	controlPlaneAccountSetupPrincipalName      = "auto-deploy-cli"
	controlPlaneAccountSetupPrincipalComponent = "byoc-account-setup-principal"
)

func controlPlaneAccountSetupPrincipalARN(accountID string) string {
	return "arn:aws:iam::" + accountID + ":role/" + controlPlaneAccountSetupPrincipalName
}

// validateControlPlaneAccountSetupPrincipal verifies the shared, inert
// compatibility principal required by the pinned official customer setup
// template. It is an account-level terraform/cp9-developer/SKILL.md resource, not
// a session resource, so activation only reads it and destroy never mutates it.
func (d *AWSDriver) validateControlPlaneAccountSetupPrincipal(ctx context.Context, input Input) (string, error) {
	expectedARN := controlPlaneAccountSetupPrincipalARN(input.ControlPlaneAccountID)
	role, err := d.readIAMRole(ctx, input, controlPlaneAccountSetupPrincipalName)
	if err != nil {
		if isAWSNotFound(err) {
			return "", fmt.Errorf(
				"required shared control-plane BYOC account-setup principal %s is missing; follow terraform/cp9-developer/SKILL.md before activation: %w",
				expectedARN,
				err,
			)
		}
		return "", fmt.Errorf("read control-plane BYOC account-setup principal %s: %w", expectedARN, err)
	}
	if role == nil || role.RoleName != controlPlaneAccountSetupPrincipalName || role.ARN != expectedARN || role.Path != "/" {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "identity or path changed")
	}
	if role.MaxSessionDuration != 3600 {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "max session duration changed")
	}
	if role.PermissionsBoundary != nil {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "permissions boundary must be absent")
	}
	if !trustPolicyExactlyDeniesPrincipal(role.AssumeRolePolicyDocument, "arn:aws:iam::"+input.ControlPlaneAccountID+":root") {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "deny-all trust policy changed")
	}
	tags := make(map[string]string, len(role.Tags))
	for _, tag := range role.Tags {
		tags[tag.Key] = tag.Value
	}
	if tags["cp9-managed"] != "true" || tags["cp9-component"] != controlPlaneAccountSetupPrincipalComponent ||
		strings.TrimSpace(tags["cp9-owner"]) == "" {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "account-level ownership tags changed")
	}
	if _, sessionTagged := tags["cp9-session"]; sessionTagged {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "shared principal must not carry cp9-session")
	}

	clients, err := d.clients(ctx, input.ControlPlaneProfile, input.Region)
	if err != nil {
		return "", err
	}
	attached, err := clients.iam.ListAttachedRolePolicies(ctx, &iam.ListAttachedRolePoliciesInput{
		RoleName: awssdk.String(controlPlaneAccountSetupPrincipalName),
	})
	if err != nil {
		return "", fmt.Errorf("read managed policies on control-plane BYOC account-setup principal %s: %w", expectedARN, err)
	}
	if len(attached.AttachedPolicies) != 0 {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "managed policies must be empty")
	}

	inline, err := clients.iam.ListRolePolicies(ctx, &iam.ListRolePoliciesInput{
		RoleName: awssdk.String(controlPlaneAccountSetupPrincipalName),
	})
	if err != nil {
		return "", fmt.Errorf("read inline policies on control-plane BYOC account-setup principal %s: %w", expectedARN, err)
	}
	if len(inline.PolicyNames) != 0 {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "inline policies must be empty")
	}

	profiles, err := clients.iam.ListInstanceProfilesForRole(ctx, &iam.ListInstanceProfilesForRoleInput{
		RoleName: awssdk.String(controlPlaneAccountSetupPrincipalName),
	})
	if err != nil {
		return "", fmt.Errorf("read instance profiles on control-plane BYOC account-setup principal %s: %w", expectedARN, err)
	}
	if len(profiles.InstanceProfiles) != 0 {
		return "", controlPlaneAccountSetupPrincipalDrift(expectedARN, "instance profiles must be empty")
	}
	return expectedARN, nil
}

func controlPlaneAccountSetupPrincipalDrift(arn, reason string) error {
	return fmt.Errorf(
		"control-plane BYOC account-setup principal %s does not match the shared inert contract (%s); follow terraform/cp9-developer/SKILL.md",
		arn,
		reason,
	)
}

func trustPolicyExactlyDeniesPrincipal(document any, principal string) bool {
	if encoded, ok := document.(string); ok {
		if json.Unmarshal([]byte(encoded), &document) != nil {
			return false
		}
	}
	documentMap, ok := document.(map[string]any)
	if !ok || len(documentMap) != 2 || documentMap["Version"] != "2012-10-17" {
		return false
	}
	statements := policyStatements(documentMap["Statement"])
	if len(statements) != 1 {
		return false
	}
	statement := statements[0]
	if len(statement) != 4 || statement["Sid"] != "DenyAllAssumeRole" || statement["Effect"] != "Deny" ||
		!equalPolicyValues(policyStringValues(statement["Action"]), []string{"sts:AssumeRole"}) {
		return false
	}
	principalMap, ok := statement["Principal"].(map[string]any)
	return ok && len(principalMap) == 1 && equalPolicyValues(
		policyStringValues(principalMap["AWS"]),
		[]string{principal},
	)
}
