################################################################################
# Environment: gcp
# Main — SentryAgent.ai AgentIdP on Google Cloud Platform
#
# Architecture:
#   Internet → Cloud Run (Google-managed TLS, auto-scaling) →
#   Cloud SQL PostgreSQL 14 (private IP, REGIONAL HA) +
#   Memorystore Redis 7 (STANDARD_HA, in-transit encryption)
#   via Serverless VPC Access connector
#
# All secrets stored in GCP Secret Manager — Cloud Run reads them at startup.
# No sensitive values in state (except where Terraform internals require it).
################################################################################

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 5.20.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = ">= 5.20.0"
    }
    random = {
      source  = "hashicorp/random"
      version = ">= 3.6.0"
    }
  }

  # Remote state — configure your backend here.
  # Example using GCS:
  #
  # backend "gcs" {
  #   bucket = "sentryagent-terraform-state"
  #   prefix = "agentidp/gcp/production"
  # }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

provider "google-beta" {
  project = var.project_id
  region  = var.region
}

################################################################################
# Enable required GCP APIs
################################################################################

resource "google_project_service" "apis" {
  for_each = toset([
    "run.googleapis.com",
    "sqladmin.googleapis.com",
    "redis.googleapis.com",
    "vpcaccess.googleapis.com",
    "secretmanager.googleapis.com",
    "servicenetworking.googleapis.com",
    "cloudresourcemanager.googleapis.com",
    "iam.googleapis.com",
  ])

  project            = var.project_id
  service            = each.value
  disable_on_destroy = false
}

################################################################################
# Locals
################################################################################

locals {
  name_prefix = "${var.project}-${var.environment}"

  common_labels = {
    environment = var.environment
    project     = replace(var.project, "-", "_")
    managed_by  = "terraform"
  }
}

################################################################################
# VPC Network
################################################################################

resource "google_compute_network" "main" {
  name                    = "${local.name_prefix}-vpc"
  auto_create_subnetworks = false
  project                 = var.project_id

  depends_on = [google_project_service.apis]
}

resource "google_compute_subnetwork" "private" {
  name          = "${local.name_prefix}-private-subnet"
  ip_cidr_range = var.vpc_cidr
  region        = var.region
  network       = google_compute_network.main.id
  project       = var.project_id

  private_ip_google_access = true

  log_config {
    aggregation_interval = "INTERVAL_10_MIN"
    flow_sampling        = 0.5
    metadata             = "INCLUDE_ALL_METADATA"
  }
}

################################################################################
# Private Services Access — required for Cloud SQL private IP
################################################################################

resource "google_compute_global_address" "private_services" {
  name          = "${local.name_prefix}-private-services-range"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 20
  network       = google_compute_network.main.id
  project       = var.project_id
}

resource "google_service_networking_connection" "private_services" {
  network                 = google_compute_network.main.id
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.private_services.name]

  depends_on = [google_project_service.apis]
}

################################################################################
# Serverless VPC Access Connector
# Cloud Run uses this to reach Cloud SQL (private IP) and Memorystore.
################################################################################

resource "google_vpc_access_connector" "main" {
  name          = "${local.name_prefix}-connector"
  region        = var.region
  project       = var.project_id
  ip_cidr_range = var.vpc_connector_cidr
  network       = google_compute_network.main.name
  min_instances = 2
  max_instances = 10
  machine_type  = "e2-micro"

  depends_on = [google_project_service.apis]
}

################################################################################
# Service Account for Cloud Run
################################################################################

resource "google_service_account" "cloud_run" {
  account_id   = "${var.project}-${var.environment}-run-sa"
  display_name = "AgentIdP Cloud Run Service Account (${var.environment})"
  project      = var.project_id
}

################################################################################
# Secret Manager — create secrets and grant the SA access
################################################################################

resource "google_secret_manager_secret" "database_url" {
  secret_id = "${local.name_prefix}-database-url"
  project   = var.project_id

  replication {
    auto {}
  }

  labels = local.common_labels

  depends_on = [google_project_service.apis]
}

resource "google_secret_manager_secret_version" "database_url" {
  secret = google_secret_manager_secret.database_url.id
  # Build the DATABASE_URL from Cloud SQL private IP output.
  secret_data = "postgresql://${var.db_username}:${var.db_password}@${google_sql_database_instance.main.private_ip_address}:5432/${var.db_name}?sslmode=require"

  depends_on = [google_sql_database_instance.main]
}

resource "google_secret_manager_secret" "redis_url" {
  secret_id = "${local.name_prefix}-redis-url"
  project   = var.project_id

  replication {
    auto {}
  }

  labels = local.common_labels

  depends_on = [google_project_service.apis]
}

resource "google_secret_manager_secret_version" "redis_url" {
  secret = google_secret_manager_secret.redis_url.id
  # Memorystore Redis with in-transit encryption uses the rediss:// scheme.
  secret_data = "rediss://${google_redis_instance.main.host}:${google_redis_instance.main.port}"

  depends_on = [google_redis_instance.main]
}

resource "google_secret_manager_secret" "jwt_private_key" {
  secret_id = "${local.name_prefix}-jwt-private-key"
  project   = var.project_id

  replication {
    auto {}
  }

  labels = local.common_labels

  depends_on = [google_project_service.apis]
}

resource "google_secret_manager_secret_version" "jwt_private_key" {
  secret      = google_secret_manager_secret.jwt_private_key.id
  secret_data = var.jwt_private_key
}

resource "google_secret_manager_secret" "jwt_public_key" {
  secret_id = "${local.name_prefix}-jwt-public-key"
  project   = var.project_id

  replication {
    auto {}
  }

  labels = local.common_labels

  depends_on = [google_project_service.apis]
}

resource "google_secret_manager_secret_version" "jwt_public_key" {
  secret      = google_secret_manager_secret.jwt_public_key.id
  secret_data = var.jwt_public_key
}

resource "google_secret_manager_secret" "vault_token" {
  count = var.vault_token != "" ? 1 : 0

  secret_id = "${local.name_prefix}-vault-token"
  project   = var.project_id

  replication {
    auto {}
  }

  labels = local.common_labels

  depends_on = [google_project_service.apis]
}

resource "google_secret_manager_secret_version" "vault_token" {
  count = var.vault_token != "" ? 1 : 0

  secret      = google_secret_manager_secret.vault_token[0].id
  secret_data = var.vault_token
}

# Grant the Cloud Run SA access to each secret
resource "google_secret_manager_secret_iam_member" "run_database_url" {
  project   = var.project_id
  secret_id = google_secret_manager_secret.database_url.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.cloud_run.email}"
}

resource "google_secret_manager_secret_iam_member" "run_redis_url" {
  project   = var.project_id
  secret_id = google_secret_manager_secret.redis_url.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.cloud_run.email}"
}

resource "google_secret_manager_secret_iam_member" "run_jwt_private_key" {
  project   = var.project_id
  secret_id = google_secret_manager_secret.jwt_private_key.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.cloud_run.email}"
}

resource "google_secret_manager_secret_iam_member" "run_jwt_public_key" {
  project   = var.project_id
  secret_id = google_secret_manager_secret.jwt_public_key.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.cloud_run.email}"
}

resource "google_secret_manager_secret_iam_member" "run_vault_token" {
  count = var.vault_token != "" ? 1 : 0

  project   = var.project_id
  secret_id = google_secret_manager_secret.vault_token[0].secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.cloud_run.email}"
}

################################################################################
# Cloud SQL — PostgreSQL 14, private IP, REGIONAL HA
################################################################################

resource "google_sql_database_instance" "main" {
  name             = "${local.name_prefix}-pg14"
  database_version = "POSTGRES_14"
  region           = var.region
  project          = var.project_id

  deletion_protection = var.deletion_protection

  settings {
    tier              = var.db_tier
    availability_type = var.db_availability_type
    disk_type         = "PD_SSD"
    disk_size         = 50
    disk_autoresize   = true

    ip_configuration {
      ipv4_enabled    = false # No public IP
      private_network = google_compute_network.main.id
      require_ssl     = true
    }

    backup_configuration {
      enabled                        = true
      start_time                     = "03:00"
      point_in_time_recovery_enabled = true
      transaction_log_retention_days = 7
      backup_retention_settings {
        retained_backups = 7
        retention_unit   = "COUNT"
      }
    }

    maintenance_window {
      day          = 7 # Sunday
      hour         = 5
      update_track = "stable"
    }

    insights_config {
      query_insights_enabled  = true
      query_string_length     = 1024
      record_application_tags = true
      record_client_address   = false
    }

    database_flags {
      name  = "log_connections"
      value = "on"
    }

    database_flags {
      name  = "log_disconnections"
      value = "on"
    }

    database_flags {
      name  = "log_min_duration_statement"
      value = "1000"
    }

    user_labels = local.common_labels
  }

  depends_on = [google_service_networking_connection.private_services]
}

resource "google_sql_database" "main" {
  name     = var.db_name
  instance = google_sql_database_instance.main.name
  project  = var.project_id
}

resource "google_sql_user" "app" {
  name     = var.db_username
  instance = google_sql_database_instance.main.name
  password = var.db_password
  project  = var.project_id
}

################################################################################
# Memorystore Redis 7 — STANDARD_HA (primary + replica), TLS enabled
################################################################################

resource "google_redis_instance" "main" {
  name           = "${local.name_prefix}-redis"
  tier           = var.memorystore_tier
  memory_size_gb = var.memorystore_memory_size_gb
  region         = var.region
  project        = var.project_id

  redis_version = var.memorystore_redis_version

  # Private connectivity via the VPC
  authorized_network = google_compute_network.main.id
  connect_mode       = "PRIVATE_SERVICE_ACCESS"

  # TLS in transit
  transit_encryption_mode = "SERVER_AUTHENTICATION"

  # No AUTH token for Memorystore — access is controlled by VPC network policy.
  # If AUTH is required, set auth_enabled = true and read the generated auth_string output.
  auth_enabled = true

  redis_configs = {
    lazyfree-lazy-eviction = "yes"
    lazyfree-lazy-expire   = "yes"
  }

  maintenance_policy {
    weekly_maintenance_window {
      day = "SUNDAY"
      start_time {
        hours   = 6
        minutes = 0
        seconds = 0
        nanos   = 0
      }
    }
  }

  labels = local.common_labels

  depends_on = [google_service_networking_connection.private_services]
}

################################################################################
# Module: AgentIdP (Cloud Run)
################################################################################

module "agentidp" {
  source = "../../modules/agentidp"

  provider_type = "gcp"
  environment   = var.environment
  project       = var.project
  app_image     = "sentryagent/agentidp:${var.app_image_tag}"
  app_port      = 3000

  gcp_project_id            = var.project_id
  gcp_region                = var.region
  gcp_service_account_email = google_service_account.cloud_run.email
  gcp_vpc_connector_name    = google_vpc_access_connector.main.id
  gcp_min_instances         = var.cloud_run_min_instances
  gcp_max_instances         = var.cloud_run_max_instances
  gcp_cpu                   = var.cloud_run_cpu
  gcp_memory                = var.cloud_run_memory
  gcp_cors_origin           = var.cors_origin
  gcp_policy_dir            = "/app/policies"
  gcp_vault_addr            = var.vault_addr
  gcp_vault_mount           = var.vault_mount

  gcp_secret_database_url_id   = google_secret_manager_secret.database_url.secret_id
  gcp_secret_redis_url_id      = google_secret_manager_secret.redis_url.secret_id
  gcp_secret_jwt_private_key_id = google_secret_manager_secret.jwt_private_key.secret_id
  gcp_secret_jwt_public_key_id = google_secret_manager_secret.jwt_public_key.secret_id
  gcp_secret_vault_token_id    = var.vault_token != "" ? google_secret_manager_secret.vault_token[0].secret_id : ""

  depends_on = [
    google_secret_manager_secret_version.database_url,
    google_secret_manager_secret_version.redis_url,
    google_secret_manager_secret_version.jwt_private_key,
    google_secret_manager_secret_version.jwt_public_key,
    google_secret_manager_secret_iam_member.run_database_url,
    google_secret_manager_secret_iam_member.run_redis_url,
    google_secret_manager_secret_iam_member.run_jwt_private_key,
    google_secret_manager_secret_iam_member.run_jwt_public_key,
  ]
}
