terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
    tls = {
      source  = "hashicorp/tls"
      version = "~> 4.0"
    }
  }
}

provider "google" {
  project = var.gcp_project_id
  region  = var.gcp_region
  # Credentials directly from GOOGLE_CREDENTIALS environment variable (set by Go application)
}

# Define common labels for resources
locals {
  common_labels = {
    lemc_scope = var.lemc_scope
    lemc_user  = var.lemc_username
    lemc_uuid  = var.lemc_uuid
  }

  # Define consistent tags using the resource prefix
  tag_ssh     = format("%s-ssh", var.resource_prefix)
  tag_backend = format("%s-backend", var.resource_prefix)

  use_existing_certificate = var.existing_ssl_certificate_name != ""
}

resource "tls_private_key" "ssh" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

resource "google_compute_network" "vpc" {
  name                    = format("%s-vpc", var.resource_prefix)
  auto_create_subnetworks = false
  project                 = var.gcp_project_id
}

resource "google_compute_subnetwork" "subnet" {
  name          = format("%s-subnet", var.resource_prefix)
  ip_cidr_range = "10.0.1.0/24"
  region        = var.gcp_region
  network       = google_compute_network.vpc.id
  project       = var.gcp_project_id
}

resource "google_compute_firewall" "allow_ssh" {
  name    = format("%s-allow-ssh", var.resource_prefix)
  network = google_compute_network.vpc.id
  project = var.gcp_project_id

  allow {
    protocol = "tcp"
    ports    = ["22"]
  }

  source_ranges = ["0.0.0.0/0"] # Allow SSH from anywhere (adjust if needed)
  target_tags   = [local.tag_ssh]
}

resource "google_compute_address" "public_ip" {
  name    = format("%s-public-ip", var.resource_prefix)
  project = var.gcp_project_id
  region  = var.gcp_region
}

resource "google_compute_instance" "vm" {
  name         = var.resource_prefix
  machine_type = var.machine_type # Or another desired machine type
  zone         = var.gcp_zone
  project      = var.gcp_project_id

  # Add the lb_backend_tag to the existing tags
  tags = [local.tag_ssh, local.tag_backend, "lemc-managed"]

  labels = local.common_labels

  boot_disk {
    initialize_params {
      image = var.image
      size  = var.boot_disk_size_gb
    }
  }

  network_interface {
    subnetwork = google_compute_subnetwork.subnet.id
    # Remove direct public IP assignment, LB will handle external access
    # Add an empty access_config block to ensure no ephemeral public IP is assigned
    access_config {}
  }

  metadata = {
    ssh-keys = "${var.lemc_username}:${tls_private_key.ssh.public_key_openssh}" # Format: username:key
  }

  service_account {
    # Uses default compute service account. Specify scopes if needed.
    scopes = ["cloud-platform"]
  }

  allow_stopping_for_update = true
}

# Firewall rule to allow ingress on all ports to backend instances.
resource "google_compute_firewall" "allow_ingress_all" {
  name    = format("%s-allow-ingress-all", var.resource_prefix)
  network = google_compute_network.vpc.id
  project = var.gcp_project_id

  allow {
    protocol = "tcp"
    ports    = ["0-65535"]
  }

  allow {
    protocol = "udp"
    ports    = ["0-65535"]
  }

  source_ranges = ["0.0.0.0/0"]
  target_tags   = [local.tag_backend]
}

# Reserve a global static IP for the Load Balancer
resource "google_compute_global_address" "lb_ip" {
  name    = format("%s-lb-ip", var.resource_prefix)
  project = var.gcp_project_id
}

# Unmanaged Instance Group for the VM
# Note: For simplicity, using unmanaged. For scaling, consider managed instance groups.
resource "google_compute_instance_group" "instance_group" {
  name        = format("%s-ig", var.resource_prefix)
  description = "Instance group for LEMC demo VM"
  zone        = var.gcp_zone
  project     = var.gcp_project_id

  instances = [
    google_compute_instance.vm.id,
  ]

  named_port {
    name = "http"
    port = var.port # Backend port
  }
}

# Health Check for the Load Balancer Backend
resource "google_compute_health_check" "lb_health_check" {
  name    = format("%s-hc", var.resource_prefix)
  project = var.gcp_project_id

  timeout_sec        = 5
  check_interval_sec = 10

  tcp_health_check {
    port = var.port # Backend port
  }
}

# Backend Service
resource "google_compute_backend_service" "backend_service" {
  name      = format("%s-bes", var.resource_prefix)
  port_name = "http" # Matches named_port in instance_group
  protocol  = "HTTP" # Protocol between LB and backend
  project   = var.gcp_project_id

  load_balancing_scheme = "EXTERNAL"
  timeout_sec           = var.backend_timeout_seconds

  backend {
    group = google_compute_instance_group.instance_group.id
  }

  health_checks = [
    google_compute_health_check.lb_health_check.id,
  ]
}

# URL Map (Basic: send all traffic to the backend service)
resource "google_compute_url_map" "url_map" {
  name            = format("%s-urlmap", var.resource_prefix)
  default_service = google_compute_backend_service.backend_service.id
  project         = var.gcp_project_id
}

# Certificate Manager Certificate Map
resource "google_certificate_manager_certificate_map" "default" {
  name    = format("%s-cert-map", var.resource_prefix)
  project = var.gcp_project_id
  labels  = local.common_labels
}

resource "google_certificate_manager_certificate_map_entry" "default" {
  count        = local.use_existing_certificate ? 1 : 0
  name         = format("%s-cert-map-entry", var.resource_prefix)
  map          = google_certificate_manager_certificate_map.default.name
  project      = var.gcp_project_id
  hostname     = var.domain_name # Ensure this matches what the certificate covers
  certificates = [format("projects/%s/locations/global/certificates/%s", var.gcp_project_id, var.existing_ssl_certificate_name)]
}

# Target HTTPS Proxy
resource "google_compute_target_https_proxy" "https_proxy" {
  count           = local.use_existing_certificate ? 1 : 0
  name            = format("%s-https-proxy", var.resource_prefix)
  url_map         = google_compute_url_map.url_map.id
  certificate_map = "//certificatemanager.googleapis.com/${google_certificate_manager_certificate_map.default.id}"
  project         = var.gcp_project_id
}

# Global Forwarding Rule for HTTPS (Port 443)
resource "google_compute_global_forwarding_rule" "https_forwarding_rule" {
  count                 = local.use_existing_certificate ? 1 : 0
  name                  = format("%s-https-fwd-rule", var.resource_prefix)
  target                = google_compute_target_https_proxy.https_proxy[0].id
  ip_address            = google_compute_global_address.lb_ip.address
  port_range            = "443"
  load_balancing_scheme = "EXTERNAL"
  project               = var.gcp_project_id
}

# Optional: Redirect HTTP to HTTPS
# Target HTTP Proxy
resource "google_compute_target_http_proxy" "http_proxy" {
  name    = format("%s-http-proxy", var.resource_prefix)
  url_map = google_compute_url_map.url_map.id # Can reuse the same URL map
  project = var.gcp_project_id
}

# Global Forwarding Rule for HTTP (Port 80)
resource "google_compute_global_forwarding_rule" "http_forwarding_rule" {
  name                  = format("%s-http-fwd-rule", var.resource_prefix)
  target                = google_compute_target_http_proxy.http_proxy.id
  ip_address            = google_compute_global_address.lb_ip.address
  port_range            = "80"
  load_balancing_scheme = "EXTERNAL"
  project               = var.gcp_project_id
}


# --- DNS Record ---

# Get details of the managed DNS zone
data "google_dns_managed_zone" "zone" {
  name    = var.dns_zone_name
  project = var.gcp_project_id # Assuming DNS zone is in the same project
}

# Create DNS A record for the domain pointing to the LB IP
resource "google_dns_record_set" "dns_record" {
  name    = "${var.domain_name}." # Ensure trailing dot
  type    = "A"
  ttl     = 300
  project = data.google_dns_managed_zone.zone.project

  managed_zone = data.google_dns_managed_zone.zone.name

  rrdatas = [google_compute_global_address.lb_ip.address]
}
