# stacksage/pricing.py
# Static pricing table for AWS resources (us-east-1 baseline)
# Prices updated: December 2025
# Source: https://aws.amazon.com/pricing/
from functools import lru_cache

# ============================================================================
# EC2 INSTANCE PRICING (hourly, us-east-1)
# ============================================================================

PRICING_EC2_HOURLY_ON_DEMAND = {
    # T3 family (burstable)
    "t3.nano": 0.0052,
    "t3.micro": 0.0104,
    "t3.small": 0.0208,
    "t3.medium": 0.0416,
    "t3.large": 0.0832,
    "t3.xlarge": 0.1664,
    "t3.2xlarge": 0.3328,
    # T2 family (previous gen burstable)
    "t2.nano": 0.0058,
    "t2.micro": 0.0116,
    "t2.small": 0.023,
    "t2.medium": 0.0464,
    "t2.large": 0.0928,
    "t2.xlarge": 0.1856,
    "t2.2xlarge": 0.3712,
    # T4g family (ARM Graviton2)
    "t4g.nano": 0.0042,
    "t4g.micro": 0.0084,
    "t4g.small": 0.0168,
    "t4g.medium": 0.0336,
    "t4g.large": 0.0672,
    # M5 family (general purpose)
    "m5.large": 0.096,
    "m5.xlarge": 0.192,
    "m5.2xlarge": 0.384,
    "m5.4xlarge": 0.768,
    "m5.8xlarge": 1.536,
    # M6i family (latest gen general purpose)
    "m6i.large": 0.096,
    "m6i.xlarge": 0.192,
    "m6i.2xlarge": 0.384,
    "m6i.4xlarge": 0.768,
    # C5 family (compute optimized)
    "c5.large": 0.085,
    "c5.xlarge": 0.17,
    "c5.2xlarge": 0.34,
    "c5.4xlarge": 0.68,
    # C6i family (latest gen compute)
    "c6i.large": 0.085,
    "c6i.xlarge": 0.17,
    "c6i.2xlarge": 0.34,
    # R5 family (memory optimized)
    "r5.large": 0.126,
    "r5.xlarge": 0.252,
    "r5.2xlarge": 0.504,
    "r5.4xlarge": 1.008,
    # R6i family (latest gen memory)
    "r6i.large": 0.126,
    "r6i.xlarge": 0.252,
    "r6i.2xlarge": 0.504,
}

# Alias for backward compatibility
PRICING_EC2_HOURLY = PRICING_EC2_HOURLY_ON_DEMAND

# ============================================================================
# EBS VOLUME PRICING ($/GB-month, us-east-1)
# ============================================================================

PRICING_EBS_GP2_GB_MONTH = 0.10  # General Purpose SSD (gp2)
PRICING_EBS_GP3_GB_MONTH = 0.08  # General Purpose SSD (gp3) - 20% cheaper
PRICING_EBS_IO1_GB_MONTH = 0.125  # Provisioned IOPS SSD (io1)
PRICING_EBS_IO2_GB_MONTH = 0.125  # Provisioned IOPS SSD (io2)
PRICING_EBS_ST1_GB_MONTH = 0.045  # Throughput Optimized HDD
PRICING_EBS_SC1_GB_MONTH = 0.015  # Cold HDD

# Legacy constant for backward compatibility
PRICING_EBS_GB_MONTH = PRICING_EBS_GP3_GB_MONTH

# EBS Snapshot pricing
PRICING_SNAPSHOT_GB_MONTH = 0.05

# ============================================================================
# RDS INSTANCE PRICING (hourly, us-east-1, Single-AZ)
# ============================================================================

PRICING_RDS_HOURLY = {
    # T3 family (burstable)
    "db.t3.micro": 0.017,
    "db.t3.small": 0.034,
    "db.t3.medium": 0.068,
    "db.t3.large": 0.136,
    "db.t3.xlarge": 0.272,
    "db.t3.2xlarge": 0.544,
    # T4g family (ARM-based, cheaper)
    "db.t4g.micro": 0.016,
    "db.t4g.small": 0.032,
    "db.t4g.medium": 0.064,
    "db.t4g.large": 0.128,
    # M5 family (general purpose)
    "db.m5.large": 0.192,
    "db.m5.xlarge": 0.384,
    "db.m5.2xlarge": 0.768,
    "db.m5.4xlarge": 1.536,
    # M6i family (latest gen)
    "db.m6i.large": 0.192,
    "db.m6i.xlarge": 0.384,
    "db.m6i.2xlarge": 0.768,
    # R5 family (memory optimized)
    "db.r5.large": 0.24,
    "db.r5.xlarge": 0.48,
    "db.r5.2xlarge": 0.96,
    "db.r5.4xlarge": 1.92,
    # R6i family (latest gen memory)
    "db.r6i.large": 0.24,
    "db.r6i.xlarge": 0.48,
    "db.r6i.2xlarge": 0.96,
}

# RDS Storage pricing ($/GB-month, us-east-1)
PRICING_RDS_STORAGE_GP2_GB_MONTH = 0.115  # General Purpose SSD (gp2)
PRICING_RDS_STORAGE_GP3_GB_MONTH = (
    0.115  # General Purpose SSD (gp3) - same price as gp2
)
PRICING_RDS_STORAGE_IO1_GB_MONTH = 0.125  # Provisioned IOPS
PRICING_RDS_STORAGE_IO1_IOPS_MONTH = 0.10  # Additional IOPS cost

# ============================================================================
# NETWORKING PRICING (us-east-1)
# ============================================================================

PRICING_NAT_HOURLY = 0.045  # NAT gateway hourly
PRICING_NAT_DATA_GB = 0.045  # NAT data processing $/GB
PRICING_EIP_UNUSED_MONTH = 4.0  # Unused Elastic IP (actually $3.60, rounded)

# Load Balancer pricing ($/hour + per-LCU charges)
PRICING_ALB_HOURLY = 0.0225  # Application Load Balancer base
PRICING_NLB_HOURLY = 0.0225  # Network Load Balancer base
PRICING_CLB_HOURLY = 0.025  # Classic Load Balancer
PRICING_ALB_LCU_HOUR = 0.008  # ALB LCU pricing
PRICING_NLB_NLCU_HOUR = 0.006  # NLB NLCU pricing

# Convert to monthly estimates (for detectors that need rough estimates)
PRICING_ALB_EST_MONTH = round(PRICING_ALB_HOURLY * 730, 2)  # ~$16.43
PRICING_NLB_EST_MONTH = round(PRICING_NLB_HOURLY * 730, 2)  # ~$16.43
PRICING_CLB_EST_MONTH = round(PRICING_CLB_HOURLY * 730, 2)  # ~$18.25
PRICING_ELB_EST_MONTH = 25.0  # Conservative average including LCU charges

# ============================================================================
# LAMBDA PRICING (us-east-1)
# ============================================================================

PRICING_LAMBDA_GB_SECOND = 0.0000166667  # $0.0000166667 per GB-second
PRICING_LAMBDA_REQUEST_MILLION = 0.20  # $0.20 per 1M requests
PRICING_LAMBDA_REQUEST_INVOCATIONS = 0.20  # $0.20 per 1M requests (per-request alias)

# ============================================================================
# API GATEWAY PRICING (us-east-1)
# ============================================================================

PRICING_API_GATEWAY_REST_REQUESTS = 3.50  # $3.50 per 1M requests (REST API)
PRICING_API_GATEWAY_HTTP_REQUESTS = 1.00  # $1.00 per 1M requests (HTTP API)
PRICING_API_GATEWAY_WEBSOCKET_MESSAGES = 1.00  # $1.00 per 1M messages

# ============================================================================
# CLOUDWATCH PRICING (us-east-1)
# ============================================================================

PRICING_CLOUDWATCH_LOGS_GB_MONTH = 0.03  # Log storage
PRICING_CLOUDWATCH_LOGS_INGESTION_GB = 0.50  # Log ingestion

# ============================================================================
# OTHER SERVICES
# ============================================================================

# AWS Fargate pricing (us-east-1 baseline)
# Notes:
# - These are for Linux x86_64 on-demand (not Windows).
# - Detectors apply REGIONAL_PRICE_MULTIPLIERS for a rough regional estimate.
PRICING_FARGATE_VCPU_HOUR = 0.04048  # $ per vCPU-hour
PRICING_FARGATE_GB_HOUR = 0.004445  # $ per GB-hour
PRICING_FARGATE_SPOT_DISCOUNT_PCT = 0.70  # Approx savings vs on-demand (pay ~30%)
PRICING_EFS_GB_MONTH = 0.30  # Elastic File System
PRICING_S3_STANDARD_GB_MONTH = 0.023  # S3 Standard storage
PRICING_S3_IA_GB_MONTH = 0.0125  # S3 Infrequent Access
PRICING_S3_GLACIER_GB_MONTH = 0.004  # S3 Glacier
PRICING_S3_IT_FREQUENT_GB_MONTH = 0.023  # S3 Intelligent-Tiering — Frequent Access tier
PRICING_S3_IT_INFREQUENT_GB_MONTH = (
    0.0125  # S3 Intelligent-Tiering — Infrequent Access tier
)
PRICING_S3_IT_MONITORING_PER_1K_OBJECTS = (
    0.0025  # S3 IT monitoring charge per 1,000 objects/month
)

# ============================================================================
# REGIONAL PRICING MULTIPLIERS (relative to us-east-1)
# ============================================================================

REGIONAL_PRICE_MULTIPLIERS = {
    # US regions
    "us-east-1": 1.0,  # N. Virginia (baseline)
    "us-east-2": 1.0,  # Ohio
    "us-west-1": 1.03,  # N. California (slightly higher)
    "us-west-2": 1.0,  # Oregon
    # Europe
    "eu-west-1": 1.05,  # Ireland
    "eu-west-2": 1.05,  # London
    "eu-central-1": 1.08,  # Frankfurt
    "eu-north-1": 1.0,  # Stockholm
    # Asia Pacific
    "ap-south-1": 1.10,  # Mumbai
    "ap-southeast-1": 1.12,  # Singapore
    "ap-southeast-2": 1.15,  # Sydney
    "ap-northeast-1": 1.13,  # Tokyo
    "ap-northeast-2": 1.10,  # Seoul
    # South America
    "sa-east-1": 1.25,  # São Paulo (most expensive)
    # Canada
    "ca-central-1": 1.02,  # Canada
}

# ============================================================================
# HELPER FUNCTIONS
# ============================================================================


def ec2_hourly_to_monthly(hourly: float) -> float:
    """Convert hourly rate to monthly cost (730 hours/month)"""
    return round(hourly * 730, 2)


def get_regional_multiplier(region: str = None) -> float:
    """Get pricing multiplier for a specific region"""
    if not region:
        return 1.0
    return REGIONAL_PRICE_MULTIPLIERS.get(region, 1.0)


# ============================================================================
# EC2 PRICING FUNCTIONS
# ============================================================================


@lru_cache(maxsize=512)
def estimate_ec2_monthly_cost(instance_type: str, region: str = None) -> float:
    """
    Estimate EC2 monthly cost with regional pricing.
    Uses static pricing table with regional multipliers.

    Args:
        instance_type: EC2 instance type (e.g., 't3.medium')
        region: AWS region (e.g., 'us-east-1'). Defaults to us-east-1 pricing.

    Returns:
        Monthly cost in USD
    """
    hourly = PRICING_EC2_HOURLY.get(instance_type, 0.05)  # Fallback: $0.05/hr
    regional_multiplier = get_regional_multiplier(region)
    return round(ec2_hourly_to_monthly(hourly * regional_multiplier), 2)


# ============================================================================
# EBS PRICING FUNCTIONS
# ============================================================================


def ebs_gb_month(size_gb: float, volume_type: str = "gp3", region: str = None) -> float:
    """
    Calculate monthly EBS storage cost with volume type differentiation.

    Args:
        size_gb: Volume size in GB
        volume_type: Volume type (gp2, gp3, io1, io2, st1, sc1)
        region: AWS region for regional pricing

    Returns:
        Monthly cost in USD
    """
    price_per_gb = {
        "gp2": PRICING_EBS_GP2_GB_MONTH,
        "gp3": PRICING_EBS_GP3_GB_MONTH,
        "io1": PRICING_EBS_IO1_GB_MONTH,
        "io2": PRICING_EBS_IO2_GB_MONTH,
        "st1": PRICING_EBS_ST1_GB_MONTH,
        "sc1": PRICING_EBS_SC1_GB_MONTH,
    }.get(volume_type.lower() if volume_type else "gp3", PRICING_EBS_GP3_GB_MONTH)

    regional_multiplier = get_regional_multiplier(region)
    return round((size_gb or 0) * price_per_gb * regional_multiplier, 2)


def snapshot_gb_month(size_gb: float, region: str = None) -> float:
    """Calculate monthly snapshot storage cost"""
    regional_multiplier = get_regional_multiplier(region)
    return round((size_gb or 0) * PRICING_SNAPSHOT_GB_MONTH * regional_multiplier, 2)


# ============================================================================
# RDS PRICING FUNCTIONS
# ============================================================================


@lru_cache(maxsize=512)
def estimate_rds_monthly_cost(
    instance_class: str,
    storage_gb: float = 0,
    storage_type: str = "gp2",
    multi_az: bool = False,
    region: str = None,
) -> float:
    """
    Estimate RDS monthly cost (instance + storage).

    Args:
        instance_class: RDS instance class (e.g., 'db.t3.medium')
        storage_gb: Allocated storage in GB
        storage_type: Storage type (gp2, gp3, io1)
        multi_az: Whether Multi-AZ is enabled (2x instance cost)
        region: AWS region

    Returns:
        Monthly cost in USD (instance + storage)
    """
    # Instance cost
    hourly = PRICING_RDS_HOURLY.get(instance_class, 0.10)  # Fallback: $0.10/hr
    if multi_az:
        hourly *= 2  # Multi-AZ doubles instance cost

    regional_multiplier = get_regional_multiplier(region)
    instance_cost = ec2_hourly_to_monthly(hourly * regional_multiplier)

    # Storage cost
    storage_price_per_gb = {
        "gp2": PRICING_RDS_STORAGE_GP2_GB_MONTH,
        "gp3": PRICING_RDS_STORAGE_GP3_GB_MONTH,
        "io1": PRICING_RDS_STORAGE_IO1_GB_MONTH,
    }.get(
        storage_type.lower() if storage_type else "gp2",
        PRICING_RDS_STORAGE_GP2_GB_MONTH,
    )

    storage_cost = round(
        (storage_gb or 0) * storage_price_per_gb * regional_multiplier, 2
    )

    return round(instance_cost + storage_cost, 2)


def estimate_rds_storage_cost(
    storage_gb: float, storage_type: str = "gp2", region: str = None
) -> float:
    """Calculate RDS storage cost only"""
    storage_price_per_gb = {
        "gp2": PRICING_RDS_STORAGE_GP2_GB_MONTH,
        "gp3": PRICING_RDS_STORAGE_GP3_GB_MONTH,
        "io1": PRICING_RDS_STORAGE_IO1_GB_MONTH,
    }.get(
        storage_type.lower() if storage_type else "gp2",
        PRICING_RDS_STORAGE_GP2_GB_MONTH,
    )

    regional_multiplier = get_regional_multiplier(region)
    return round((storage_gb or 0) * storage_price_per_gb * regional_multiplier, 2)


# ============================================================================
# LAMBDA PRICING FUNCTIONS
# ============================================================================


def estimate_lambda_monthly_cost(
    memory_mb: int,
    avg_duration_ms: float,
    invocations_per_month: int,
    region: str = None,
) -> float:
    """
    Estimate Lambda monthly cost (compute + requests).

    Args:
        memory_mb: Function memory allocation in MB
        avg_duration_ms: Average execution duration in milliseconds
        invocations_per_month: Number of invocations per month
        region: AWS region

    Returns:
        Monthly cost in USD (compute + requests)
    """
    # Compute cost (GB-seconds)
    memory_gb = memory_mb / 1024
    duration_seconds = avg_duration_ms / 1000
    gb_seconds = memory_gb * duration_seconds * invocations_per_month

    regional_multiplier = get_regional_multiplier(region)
    compute_cost = gb_seconds * PRICING_LAMBDA_GB_SECOND * regional_multiplier

    # Request cost
    request_cost = (
        (invocations_per_month / 1_000_000)
        * PRICING_LAMBDA_REQUEST_MILLION
        * regional_multiplier
    )

    return round(compute_cost + request_cost, 2)


# ============================================================================
# NETWORKING PRICING FUNCTIONS
# ============================================================================


def nat_month(
    hourly: float = PRICING_NAT_HOURLY, data_gb: float = 0.0, region: str = None
) -> float:
    """Calculate NAT Gateway monthly cost (hourly + data processing)"""
    regional_multiplier = get_regional_multiplier(region)
    hourly_cost = ec2_hourly_to_monthly(hourly * regional_multiplier)
    data_cost = (data_gb or 0) * PRICING_NAT_DATA_GB * regional_multiplier
    return round(hourly_cost + data_cost, 2)


def eip_unused_month(region: str = None) -> float:
    """Calculate unused Elastic IP monthly cost"""
    regional_multiplier = get_regional_multiplier(region)
    return round(PRICING_EIP_UNUSED_MONTH * regional_multiplier, 2)


def elb_monthly_cost(lb_type: str = "alb", region: str = None) -> float:
    """
    Estimate Load Balancer monthly cost (base hourly only, not including LCU charges).

    Args:
        lb_type: Load balancer type ('alb', 'nlb', 'classic')
        region: AWS region

    Returns:
        Monthly base cost in USD (excluding LCU/NLCU charges)
    """
    hourly = {
        "alb": PRICING_ALB_HOURLY,
        "nlb": PRICING_NLB_HOURLY,
        "classic": PRICING_CLB_HOURLY,
    }.get(lb_type.lower(), PRICING_ALB_HOURLY)

    regional_multiplier = get_regional_multiplier(region)
    return round(ec2_hourly_to_monthly(hourly * regional_multiplier), 2)


# ============================================================================
# CLOUDWATCH PRICING FUNCTIONS
# ============================================================================


def cloudwatch_logs_storage_cost(size_gb: float, region: str = None) -> float:
    """Calculate CloudWatch Logs storage cost"""
    regional_multiplier = get_regional_multiplier(region)
    return round(
        (size_gb or 0) * PRICING_CLOUDWATCH_LOGS_GB_MONTH * regional_multiplier, 2
    )


# ============================================================================
# BACKWARD COMPATIBILITY WRAPPERS
# ============================================================================
# These maintain compatibility with existing detector code


def eip_unused_month_legacy() -> float:
    """Legacy function for backward compatibility (no region param)"""
    return PRICING_EIP_UNUSED_MONTH


# ============================================================================
# DYNAMODB PRICING
# ============================================================================

# DynamoDB Provisioned Capacity (hourly rates, us-east-1)
PRICING_DYNAMODB_RCU_HOURLY = 0.00013  # Read Capacity Unit per hour
PRICING_DYNAMODB_WCU_HOURLY = 0.00065  # Write Capacity Unit per hour
PRICING_DYNAMODB_STORAGE_GB_MONTH = 0.25  # Storage per GB-month

# DynamoDB On-Demand (per million requests)
PRICING_DYNAMODB_ON_DEMAND_READ_PER_MILLION = 0.25
PRICING_DYNAMODB_ON_DEMAND_WRITE_PER_MILLION = 1.25


# ============================================================================
# ELASTICACHE PRICING (hourly rates, us-east-1)
# ============================================================================

PRICING_ELASTICACHE_HOURLY = {
    # T3 family
    "cache.t3.micro": 0.017,
    "cache.t3.small": 0.034,
    "cache.t3.medium": 0.068,
    # T4g family (Graviton2)
    "cache.t4g.micro": 0.016,
    "cache.t4g.small": 0.032,
    "cache.t4g.medium": 0.064,
    # M5 family
    "cache.m5.large": 0.154,
    "cache.m5.xlarge": 0.308,
    "cache.m5.2xlarge": 0.616,
    # M6g family (Graviton2)
    "cache.m6g.large": 0.139,
    "cache.m6g.xlarge": 0.278,
    # R5 family (memory optimized)
    "cache.r5.large": 0.201,
    "cache.r5.xlarge": 0.402,
    "cache.r5.2xlarge": 0.804,
    # R6g family (Graviton2)
    "cache.r6g.large": 0.181,
    "cache.r6g.xlarge": 0.362,
}


# ============================================================================
# CLOUDFRONT PRICING
# ============================================================================

# CloudFront has complex pricing based on data transfer and requests
# For unused distributions, cost is minimal (just metadata/control plane)
PRICING_CLOUDFRONT_UNUSED_BASELINE_MONTH = 1.00  # Conservative estimate


# ============================================================================
# ROUTE 53 PRICING
# ============================================================================

PRICING_ROUTE53_HOSTED_ZONE_PUBLIC_MONTH = 0.50  # Public hosted zone
PRICING_ROUTE53_HOSTED_ZONE_PRIVATE_MONTH = 50.00  # Private VPC hosted zone
