"""
DigitalOcean Infrastructure for Amar Mascotas

Deploys:
- VPC for network isolation
- Droplet for Django app + Celery
- Managed PostgreSQL (with PostGIS via extension)
- Managed Redis
- Firewall rules
- (Optional) Load Balancer, Domain records

Estimated cost: ~$66/month
"""

import pulumi
import pulumi_digitalocean as do
import sys
sys.path.append("..")
from shared.config import get_config, APP_SERVER_INIT_SCRIPT

# Load configuration
cfg = get_config()

# =============================================================================
# NETWORKING
# =============================================================================

# VPC for private networking between resources
vpc = do.Vpc(
    f"{cfg.resource_prefix}-vpc",
    name=f"{cfg.resource_prefix}-vpc",
    region="nyc1",
    ip_range="10.10.10.0/24",
)

# =============================================================================
# DATABASE - Managed PostgreSQL
# =============================================================================

# DigitalOcean managed Postgres (PostGIS available as extension)
db_cluster = do.DatabaseCluster(
    f"{cfg.resource_prefix}-db",
    name=f"{cfg.resource_prefix}-db",
    engine="pg",
    version=cfg.db_version,
    size="db-s-1vcpu-1gb",      # $15/mo - smallest managed DB
    region="nyc1",
    node_count=1,               # Single node (use 2+ for HA)
    private_network_uuid=vpc.id,
    tags=[cfg.environment],
)

# Create application database
db = do.DatabaseDb(
    f"{cfg.resource_prefix}-database",
    cluster_id=db_cluster.id,
    name=cfg.db_name,
)

# Create database user
db_user = do.DatabaseUser(
    f"{cfg.resource_prefix}-db-user",
    cluster_id=db_cluster.id,
    name=cfg.db_user,
)

# =============================================================================
# CACHE - Managed Redis
# =============================================================================

redis_cluster = do.DatabaseCluster(
    f"{cfg.resource_prefix}-redis",
    name=f"{cfg.resource_prefix}-redis",
    engine="redis",
    version=cfg.redis_version,
    size="db-s-1vcpu-1gb",      # $15/mo
    region="nyc1",
    node_count=1,
    private_network_uuid=vpc.id,
    tags=[cfg.environment],
)

# =============================================================================
# COMPUTE - Droplet
# =============================================================================

# SSH key (you should create this beforehand or import existing)
# ssh_key = do.SshKey(
#     f"{cfg.resource_prefix}-ssh-key",
#     name=f"{cfg.resource_prefix}-key",
#     public_key=open("~/.ssh/id_rsa.pub").read(),
# )

# Use existing SSH keys (fetch by name or fingerprint)
ssh_keys = do.get_ssh_keys()

# App server droplet
droplet = do.Droplet(
    f"{cfg.resource_prefix}-app",
    name=f"{cfg.resource_prefix}-app",
    image="ubuntu-22-04-x64",
    size="s-2vcpu-4gb",         # $24/mo - 4GB RAM, 2 vCPU
    region="nyc1",
    vpc_uuid=vpc.id,
    ssh_keys=[k.id for k in ssh_keys.ssh_keys[:1]] if ssh_keys.ssh_keys else [],
    user_data=APP_SERVER_INIT_SCRIPT,
    tags=[cfg.environment, "app"],
    opts=pulumi.ResourceOptions(depends_on=[db_cluster, redis_cluster]),
)

# =============================================================================
# FIREWALL
# =============================================================================

firewall = do.Firewall(
    f"{cfg.resource_prefix}-firewall",
    name=f"{cfg.resource_prefix}-firewall",
    droplet_ids=[droplet.id],

    # Inbound rules
    inbound_rules=[
        # SSH (restrict to specific IPs in production)
        do.FirewallInboundRuleArgs(
            protocol="tcp",
            port_range="22",
            source_addresses=cfg.allowed_ssh_ips or ["0.0.0.0/0", "::/0"],
        ),
        # HTTP
        do.FirewallInboundRuleArgs(
            protocol="tcp",
            port_range="80",
            source_addresses=["0.0.0.0/0", "::/0"],
        ),
        # HTTPS
        do.FirewallInboundRuleArgs(
            protocol="tcp",
            port_range="443",
            source_addresses=["0.0.0.0/0", "::/0"],
        ),
    ],

    # Outbound rules (allow all outbound)
    outbound_rules=[
        do.FirewallOutboundRuleArgs(
            protocol="tcp",
            port_range="1-65535",
            destination_addresses=["0.0.0.0/0", "::/0"],
        ),
        do.FirewallOutboundRuleArgs(
            protocol="udp",
            port_range="1-65535",
            destination_addresses=["0.0.0.0/0", "::/0"],
        ),
        do.FirewallOutboundRuleArgs(
            protocol="icmp",
            destination_addresses=["0.0.0.0/0", "::/0"],
        ),
    ],
)

# =============================================================================
# DATABASE FIREWALL - Only allow app server
# =============================================================================

db_firewall = do.DatabaseFirewall(
    f"{cfg.resource_prefix}-db-firewall",
    cluster_id=db_cluster.id,
    rules=[
        do.DatabaseFirewallRuleArgs(
            type="droplet",
            value=droplet.id,
        ),
    ],
)

redis_firewall = do.DatabaseFirewall(
    f"{cfg.resource_prefix}-redis-firewall",
    cluster_id=redis_cluster.id,
    rules=[
        do.DatabaseFirewallRuleArgs(
            type="droplet",
            value=droplet.id,
        ),
    ],
)

# =============================================================================
# OPTIONAL: Load Balancer (uncomment if needed)
# =============================================================================

# load_balancer = do.LoadBalancer(
#     f"{cfg.resource_prefix}-lb",
#     name=f"{cfg.resource_prefix}-lb",
#     region="nyc1",
#     vpc_uuid=vpc.id,
#     droplet_ids=[droplet.id],
#     forwarding_rules=[
#         do.LoadBalancerForwardingRuleArgs(
#             entry_port=443,
#             entry_protocol="https",
#             target_port=80,
#             target_protocol="http",
#             certificate_name=f"{cfg.resource_prefix}-cert",
#         ),
#         do.LoadBalancerForwardingRuleArgs(
#             entry_port=80,
#             entry_protocol="http",
#             target_port=80,
#             target_protocol="http",
#         ),
#     ],
#     healthcheck=do.LoadBalancerHealthcheckArgs(
#         port=80,
#         protocol="http",
#         path="/health/",
#     ),
# )

# =============================================================================
# OPTIONAL: DNS Records (uncomment if managing domain in DO)
# =============================================================================

# domain = do.Domain(
#     f"{cfg.resource_prefix}-domain",
#     name=cfg.domain,
# )
#
# api_record = do.DnsRecord(
#     f"{cfg.resource_prefix}-api-dns",
#     domain=domain.name,
#     type="A",
#     name="backoffice",
#     value=droplet.ipv4_address,
#     ttl=300,
# )

# =============================================================================
# OUTPUTS
# =============================================================================

pulumi.export("droplet_ip", droplet.ipv4_address)
pulumi.export("droplet_private_ip", droplet.ipv4_address_private)
pulumi.export("db_host", db_cluster.private_host)
pulumi.export("db_port", db_cluster.port)
pulumi.export("db_name", cfg.db_name)
pulumi.export("db_user", cfg.db_user)
pulumi.export("db_password", db_user.password)
pulumi.export("redis_host", redis_cluster.private_host)
pulumi.export("redis_port", redis_cluster.port)
pulumi.export("redis_password", redis_cluster.password)

# Generate .env content for easy deployment
pulumi.export("env_file", pulumi.Output.all(
    db_cluster.private_host,
    db_cluster.port,
    db_user.password,
    redis_cluster.private_host,
    redis_cluster.port,
    redis_cluster.password,
).apply(lambda args: f"""
# Generated by Pulumi - DigitalOcean
DB_HOST={args[0]}
DB_PORT={args[1]}
DB_NAME={cfg.db_name}
DB_USER={cfg.db_user}
DB_PASSWORD={args[2]}
CELERY_BROKER_URL=rediss://default:{args[5]}@{args[3]}:{args[4]}
CELERY_RESULT_BACKEND=rediss://default:{args[5]}@{args[3]}:{args[4]}
"""))
