"""
Google Cloud Platform Infrastructure for Amar Mascotas

Deploys:
- VPC with subnets
- Compute Engine instance for Django app + Celery
- Cloud SQL PostgreSQL (PostGIS via flags)
- Memorystore Redis
- Firewall rules
- (Optional) Cloud Load Balancer, Cloud DNS

Estimated cost: ~$93/month

NOTE: GCP has good free tier credits and competitive pricing.
      PostGIS requires enabling the `cloudsql.enable_pgaudit` flag.
"""

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

# Load configuration
cfg = get_config()

# Get project
project = gcp.organizations.get_project()

# =============================================================================
# NETWORKING - VPC
# =============================================================================

# VPC Network
vpc = gcp.compute.Network(
    f"{cfg.resource_prefix}-vpc",
    name=f"{cfg.resource_prefix}-vpc",
    auto_create_subnetworks=False,
    description="VPC for Amar Mascotas",
)

# Subnet for compute resources
subnet = gcp.compute.Subnetwork(
    f"{cfg.resource_prefix}-subnet",
    name=f"{cfg.resource_prefix}-subnet",
    ip_cidr_range="10.0.1.0/24",
    region="us-east1",
    network=vpc.id,
    private_ip_google_access=True,  # Access Google APIs without public IP
)

# =============================================================================
# FIREWALL RULES
# =============================================================================

# Allow SSH
firewall_ssh = gcp.compute.Firewall(
    f"{cfg.resource_prefix}-allow-ssh",
    name=f"{cfg.resource_prefix}-allow-ssh",
    network=vpc.name,
    allows=[
        gcp.compute.FirewallAllowArgs(
            protocol="tcp",
            ports=["22"],
        ),
    ],
    source_ranges=cfg.allowed_ssh_ips or ["0.0.0.0/0"],
    target_tags=["app-server"],
)

# Allow HTTP/HTTPS
firewall_http = gcp.compute.Firewall(
    f"{cfg.resource_prefix}-allow-http",
    name=f"{cfg.resource_prefix}-allow-http",
    network=vpc.name,
    allows=[
        gcp.compute.FirewallAllowArgs(
            protocol="tcp",
            ports=["80", "443"],
        ),
    ],
    source_ranges=["0.0.0.0/0"],
    target_tags=["app-server"],
)

# Allow internal traffic (for DB/Redis access)
firewall_internal = gcp.compute.Firewall(
    f"{cfg.resource_prefix}-allow-internal",
    name=f"{cfg.resource_prefix}-allow-internal",
    network=vpc.name,
    allows=[
        gcp.compute.FirewallAllowArgs(
            protocol="tcp",
            ports=["0-65535"],
        ),
        gcp.compute.FirewallAllowArgs(
            protocol="udp",
            ports=["0-65535"],
        ),
        gcp.compute.FirewallAllowArgs(
            protocol="icmp",
        ),
    ],
    source_ranges=["10.0.0.0/8"],
)

# =============================================================================
# DATABASE - Cloud SQL PostgreSQL
# =============================================================================

# Cloud SQL instance
# Note: PostGIS available via database flags
db_instance = gcp.sql.DatabaseInstance(
    f"{cfg.resource_prefix}-db",
    name=f"{cfg.resource_prefix}-db",
    database_version="POSTGRES_15",
    region="us-east1",
    deletion_protection=False,          # Set True for production!
    settings=gcp.sql.DatabaseInstanceSettingsArgs(
        tier="db-f1-micro",             # $25/mo - smallest
        disk_size=10,
        disk_type="PD_SSD",
        ip_configuration=gcp.sql.DatabaseInstanceSettingsIpConfigurationArgs(
            ipv4_enabled=False,
            private_network=vpc.id,
            enable_private_path_for_google_cloud_services=True,
        ),
        backup_configuration=gcp.sql.DatabaseInstanceSettingsBackupConfigurationArgs(
            enabled=True,
            start_time="03:00",
        ),
        database_flags=[
            # Enable PostGIS extensions
            gcp.sql.DatabaseInstanceSettingsDatabaseFlagArgs(
                name="cloudsql.enable_pg_cron",
                value="on",
            ),
        ],
        user_labels=cfg.tags,
    ),
    opts=pulumi.ResourceOptions(depends_on=[vpc]),
)

# Database
db = gcp.sql.Database(
    f"{cfg.resource_prefix}-database",
    name=cfg.db_name,
    instance=db_instance.name,
)

# Database user
db_user = gcp.sql.User(
    f"{cfg.resource_prefix}-db-user",
    name=cfg.db_user,
    instance=db_instance.name,
    password=pulumi.Config().require_secret("db_password"),
)

# Private IP for Cloud SQL
private_ip_address = gcp.compute.GlobalAddress(
    f"{cfg.resource_prefix}-db-private-ip",
    name=f"{cfg.resource_prefix}-db-private-ip",
    purpose="VPC_PEERING",
    address_type="INTERNAL",
    prefix_length=16,
    network=vpc.id,
)

# VPC peering for Cloud SQL
private_vpc_connection = gcp.servicenetworking.Connection(
    f"{cfg.resource_prefix}-private-vpc-connection",
    network=vpc.id,
    service="servicenetworking.googleapis.com",
    reserved_peering_ranges=[private_ip_address.name],
)

# =============================================================================
# CACHE - Memorystore Redis
# =============================================================================

redis_instance = gcp.redis.Instance(
    f"{cfg.resource_prefix}-redis",
    name=f"{cfg.resource_prefix}-redis",
    tier="BASIC",                        # $20/mo - no HA
    memory_size_gb=1,
    region="us-east1",
    redis_version="REDIS_7_0",
    authorized_network=vpc.id,
    connect_mode="PRIVATE_SERVICE_ACCESS",
    labels=cfg.tags,
    opts=pulumi.ResourceOptions(depends_on=[private_vpc_connection]),
)

# =============================================================================
# COMPUTE - Compute Engine Instance
# =============================================================================

# Service account for the instance
service_account = gcp.serviceaccount.Account(
    f"{cfg.resource_prefix}-sa",
    account_id=f"{cfg.resource_prefix}-app-sa",
    display_name="Amar App Service Account",
)

# Compute instance
instance = gcp.compute.Instance(
    f"{cfg.resource_prefix}-app",
    name=f"{cfg.resource_prefix}-app",
    machine_type="e2-medium",            # $30/mo - 4GB RAM, 2 vCPU
    zone="us-east1-b",
    tags=["app-server"],
    boot_disk=gcp.compute.InstanceBootDiskArgs(
        initialize_params=gcp.compute.InstanceBootDiskInitializeParamsArgs(
            image="ubuntu-os-cloud/ubuntu-2204-lts",
            size=30,
            type="pd-ssd",
        ),
    ),
    network_interfaces=[
        gcp.compute.InstanceNetworkInterfaceArgs(
            network=vpc.id,
            subnetwork=subnet.id,
            access_configs=[
                gcp.compute.InstanceNetworkInterfaceAccessConfigArgs(
                    # Ephemeral public IP
                ),
            ],
        ),
    ],
    service_account=gcp.compute.InstanceServiceAccountArgs(
        email=service_account.email,
        scopes=["cloud-platform"],
    ),
    metadata_startup_script=APP_SERVER_INIT_SCRIPT,
    labels=cfg.tags,
)

# Static external IP (optional, costs extra)
static_ip = gcp.compute.Address(
    f"{cfg.resource_prefix}-static-ip",
    name=f"{cfg.resource_prefix}-static-ip",
    region="us-east1",
)

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

# health_check = gcp.compute.HealthCheck(
#     f"{cfg.resource_prefix}-health-check",
#     name=f"{cfg.resource_prefix}-health-check",
#     http_health_check=gcp.compute.HealthCheckHttpHealthCheckArgs(
#         port=80,
#         request_path="/health/",
#     ),
# )

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

pulumi.export("instance_public_ip", instance.network_interfaces[0].access_configs[0].nat_ip)
pulumi.export("instance_private_ip", instance.network_interfaces[0].network_ip)
pulumi.export("static_ip", static_ip.address)
pulumi.export("db_private_ip", db_instance.private_ip_address)
pulumi.export("db_connection_name", db_instance.connection_name)
pulumi.export("db_name", cfg.db_name)
pulumi.export("db_user", cfg.db_user)
pulumi.export("redis_host", redis_instance.host)
pulumi.export("redis_port", redis_instance.port)

# Generate .env content
pulumi.export("env_file", pulumi.Output.all(
    db_instance.private_ip_address,
    redis_instance.host,
    redis_instance.port,
).apply(lambda args: f"""
# Generated by Pulumi - GCP
DB_HOST={args[0]}
DB_PORT=5432
DB_NAME={cfg.db_name}
DB_USER={cfg.db_user}
DB_PASSWORD=<set via pulumi config>
CELERY_BROKER_URL=redis://{args[1]}:{args[2]}/0
CELERY_RESULT_BACKEND=redis://{args[1]}:{args[2]}/0
"""))
