// Package aws provides AWS resource tracking, cleanup, cost reporting,
// and credential injection for cp9 local development environments.
package aws

import (
	"context"
	"fmt"
	"strings"
	"time"
)

// Tag keys used to track cp9-managed AWS resources.
const (
	TagSession = "cp9-session"
	TagOwner   = "cp9-owner"
	TagManaged = "cp9-managed"
	TagTTL     = "cp9-ttl"

	TagManagedTerraformSubstrate = "terraform-substrate"
)

// ResourceType identifies the AWS service that owns a resource.
type ResourceType string

const (
	ResourceEKSCluster           ResourceType = "eks-cluster"
	ResourceEKSNodegroup         ResourceType = "eks-nodegroup"
	ResourceEKSPodIdentity       ResourceType = "eks-pod-identity-association"
	ResourceACMPCACertAuthority  ResourceType = "acm-pca-certificate-authority"
	ResourceCloudFormationStack  ResourceType = "cloudformation-stack"
	ResourceVPC                  ResourceType = "vpc"
	ResourceSubnet               ResourceType = "subnet"
	ResourceRouteTable           ResourceType = "route-table"
	ResourceInternetGateway      ResourceType = "internet-gateway"
	ResourceNATGateway           ResourceType = "nat-gateway"
	ResourceVPCEndpoint          ResourceType = "vpc-endpoint"
	ResourceVPCEndpointService   ResourceType = "vpc-endpoint-service"
	ResourceEIP                  ResourceType = "eip"
	ResourceLaunchTemplate       ResourceType = "launch-template"
	ResourceEC2ConnectEndpoint   ResourceType = "ec2-instance-connect-endpoint"
	ResourceEC2PlacementGroup    ResourceType = "ec2-placement-group"
	ResourceEC2Instance          ResourceType = "ec2-instance"
	ResourceAutoScalingGroup     ResourceType = "autoscaling-group"
	ResourceEC2KeyPair           ResourceType = "ec2-key-pair"
	ResourceEBSVolume            ResourceType = "ebs-volume"
	ResourceEBSSnapshot          ResourceType = "ebs-snapshot"
	ResourceENI                  ResourceType = "eni"
	ResourceSecurityGroup        ResourceType = "security-group"
	ResourceIAMRole              ResourceType = "iam-role"
	ResourceIAMInstanceProfile   ResourceType = "iam-instance-profile"
	ResourceIAMPolicy            ResourceType = "iam-policy"
	ResourceRoute53HostedZone    ResourceType = "route53-hosted-zone"
	ResourceLoadBalancer         ResourceType = "load-balancer"
	ResourceTargetGroup          ResourceType = "target-group"
	ResourceSQS                  ResourceType = "sqs"
	ResourceS3                   ResourceType = "s3"
	ResourceDynamoDB             ResourceType = "dynamodb"
	ResourceSNS                  ResourceType = "sns"
	ResourceLambda               ResourceType = "lambda"
	ResourceSecretsManagerSecret ResourceType = "secretsmanager-secret"
	ResourceECR                  ResourceType = "ecr"
	ResourceMSKCluster           ResourceType = "msk-cluster"
	ResourceKMSKey               ResourceType = "kms-key"
	ResourceUnknown              ResourceType = "unknown"
)

// Resource represents a single AWS resource discovered via tagging.
type Resource struct {
	ARN       string       `json:"arn"`
	Type      ResourceType `json:"type"`
	Region    string       `json:"region,omitempty"`
	SessionID string       `json:"session_id"`
	Owner     string       `json:"owner"`
}

// String returns a human-readable representation.
func (r *Resource) String() string {
	return fmt.Sprintf("%s (%s) region=%s session=%s owner=%s", r.ARN, r.Type, r.Region, r.SessionID, r.Owner)
}

// CleanupResult holds the outcome of deleting a single resource.
type CleanupResult struct {
	ARN     string       `json:"arn"`
	Type    ResourceType `json:"type"`
	Deleted bool         `json:"deleted"`
	Error   string       `json:"error,omitempty"`
}

// SessionInfo holds metadata about a tracked cp9 session for reaping.
type SessionInfo struct {
	SessionID string    `json:"session_id"`
	Owner     string    `json:"owner"`
	CreatedAt time.Time `json:"created_at"`
	Resources int       `json:"resources"`
}

// Tracker discovers AWS resources by cp9 tags.
type Tracker interface {
	// FindBySession returns all resources tagged with the given session ID.
	FindBySession(ctx context.Context, sessionID string) ([]Resource, error)

	// FindByOwner returns all resources tagged with the given owner.
	FindByOwner(ctx context.Context, owner string) ([]Resource, error)

	// FindAll returns all cp9-tagged resources (any session).
	FindAll(ctx context.Context) ([]Resource, error)
}

// Cleaner deletes AWS resources by type.
type Cleaner interface {
	// Delete removes the resource identified by ARN.
	// Returns true if the resource was deleted, false if it was already gone.
	Delete(ctx context.Context, r *Resource) (bool, error)
}

// CostReporter retrieves per-session AWS spend.
type CostReporter interface {
	// SessionCost returns the estimated cost for resources tagged with the session.
	SessionCost(ctx context.Context, sessionID string, start, end time.Time) ([]CostEntry, error)
}

// CostEntry holds per-resource cost data.
type CostEntry struct {
	Service string  `json:"service"`
	Amount  float64 `json:"amount"`
	Unit    string  `json:"unit"`
}

// ParseResourceType extracts the service type from an ARN.
// ARN format: arn:aws:service:region:account:resource
// SessionHostNameTag is the Name tag value cp9 gives a session's Remote Dev
// host. It has two consumers -- the ec2k3d adapter that creates the host, and
// cleanup, which selects the host by this exact value -- so it lives here rather
// than being spelled out at both ends. Re-deriving it independently would let the
// selector silently match nothing if the producer ever changed.
func SessionHostNameTag(session string) string {
	return "cp9-" + strings.TrimSpace(session)
}

func ParseResourceType(arn string) ResourceType {
	parts := strings.SplitN(arn, ":", 6)
	if len(parts) < 6 {
		return ResourceUnknown
	}
	service := parts[2]
	resource := parts[5]

	switch service {
	case "eks":
		switch {
		case strings.HasPrefix(resource, "cluster/"):
			return ResourceEKSCluster
		case strings.HasPrefix(resource, "nodegroup/"):
			return ResourceEKSNodegroup
		case strings.HasPrefix(resource, "podidentityassociation/"):
			return ResourceEKSPodIdentity
		}
	case "acm-pca":
		if strings.HasPrefix(resource, "certificate-authority/") {
			return ResourceACMPCACertAuthority
		}
	case "cloudformation":
		// arn:aws:cloudformation:<region>:<account>:stack/<name>/<id>
		if strings.HasPrefix(resource, "stack/") {
			return ResourceCloudFormationStack
		}
	case "autoscaling":
		if strings.Contains(resource, "autoScalingGroupName/") {
			return ResourceAutoScalingGroup
		}
	case "ec2":
		switch {
		case strings.HasPrefix(resource, "vpc/"):
			return ResourceVPC
		case strings.HasPrefix(resource, "subnet/"):
			return ResourceSubnet
		case strings.HasPrefix(resource, "route-table/"):
			return ResourceRouteTable
		case strings.HasPrefix(resource, "internet-gateway/"):
			return ResourceInternetGateway
		case strings.HasPrefix(resource, "natgateway/"):
			return ResourceNATGateway
		case strings.HasPrefix(resource, "vpc-endpoint/"):
			return ResourceVPCEndpoint
		case strings.HasPrefix(resource, "vpc-endpoint-service/"):
			return ResourceVPCEndpointService
		case strings.HasPrefix(resource, "elastic-ip/"):
			return ResourceEIP
		case strings.HasPrefix(resource, "launch-template/"):
			return ResourceLaunchTemplate
		case strings.HasPrefix(resource, "instance-connect-endpoint/"):
			return ResourceEC2ConnectEndpoint
		case strings.HasPrefix(resource, "placement-group/"):
			return ResourceEC2PlacementGroup
		case strings.HasPrefix(resource, "instance/"):
			return ResourceEC2Instance
		case strings.HasPrefix(resource, "key-pair/"):
			return ResourceEC2KeyPair
		case strings.HasPrefix(resource, "volume/"):
			return ResourceEBSVolume
		case strings.HasPrefix(resource, "snapshot/"):
			return ResourceEBSSnapshot
		case strings.HasPrefix(resource, "network-interface/"):
			return ResourceENI
		case strings.HasPrefix(resource, "security-group/"):
			return ResourceSecurityGroup
		}
	case "iam":
		switch {
		case strings.HasPrefix(resource, "role/"):
			return ResourceIAMRole
		case strings.HasPrefix(resource, "instance-profile/"):
			return ResourceIAMInstanceProfile
		case strings.HasPrefix(resource, "policy/"):
			return ResourceIAMPolicy
		}
	case "route53":
		if strings.HasPrefix(resource, "hostedzone/") {
			return ResourceRoute53HostedZone
		}
	case "elasticloadbalancing":
		switch {
		case strings.HasPrefix(resource, "loadbalancer/"):
			return ResourceLoadBalancer
		case strings.HasPrefix(resource, "targetgroup/"):
			return ResourceTargetGroup
		}
	case "sqs":
		return ResourceSQS
	case "s3":
		return ResourceS3
	case "dynamodb":
		return ResourceDynamoDB
	case "sns":
		return ResourceSNS
	case "lambda":
		return ResourceLambda
	case "ecr":
		if strings.HasPrefix(resource, "repository/") {
			return ResourceECR
		}
	case "secretsmanager":
		if strings.HasPrefix(resource, "secret:") {
			return ResourceSecretsManagerSecret
		}
	case "kafka":
		if strings.HasPrefix(resource, "cluster/") {
			return ResourceMSKCluster
		}
	case "kms":
		if strings.HasPrefix(resource, "key/") {
			return ResourceKMSKey
		}
	}
	return ResourceUnknown
}

// ParseResourceRegion extracts the region field from an ARN when present.
func ParseResourceRegion(arn string) string {
	parts := strings.SplitN(arn, ":", 6)
	if len(parts) < 4 {
		return ""
	}
	return parts[3]
}
