terraform {
  required_version = ">= 1.9"

  required_providers {
    coder = {
      source  = "coder/coder"
      version = ">= 2.12"
    }
  }
}

variable "agent_id" {
  type        = string
  description = "The ID of a Coder agent."
}

data "coder_workspace" "me" {}

data "coder_workspace_owner" "me" {}

variable "icon" {
  type        = string
  description = "The icon to use for the app."
  default     = "/icon/openai.svg"
}

variable "workdir" {
  type        = string
  description = "Optional project directory. When set, the module pre-creates it if missing and adds it as a trusted project in Codex config.toml."
  default     = null
}

variable "pre_install_script" {
  type        = string
  description = "Custom script to run before installing Codex."
  default     = null
}

variable "post_install_script" {
  type        = string
  description = "Custom script to run after installing Codex."
  default     = null
}

variable "install_codex" {
  type        = bool
  description = "Whether to install Codex."
  default     = true
}

variable "codex_version" {
  type        = string
  description = "The version of Codex to install."
  default     = "latest"
}

variable "openai_api_key" {
  type        = string
  description = "OpenAI API key for Codex CLI."
  sensitive   = true
  default     = ""
}

variable "base_config_toml" {
  type        = string
  description = <<-EOT
    Complete base TOML configuration for Codex (without mcp_servers section).
    When empty, the module generates a minimal default:

      preferred_auth_method = "apikey"
      # model_provider = "aigateway"           (sets the default profile, when enable_ai_gateway = true)
      # model_reasoning_effort = "<value>"    (sets the reasoning effort, when model_reasoning_effort is set)

      [projects."<workdir>"]                  (when workdir is set)
      trust_level = "trusted"

    When non-empty, the value is written verbatim as the base of config.toml;
    mcp and AI Gateway sections are still appended after it.
    Note: model_reasoning_effort and workdir trust are only applied in the
    default config. Include them in your custom config if needed.
  EOT
  default     = ""
}

variable "mcp" {
  type        = string
  description = "MCP server configurations in TOML format. When set, servers are appended to the Codex config.toml."
  default     = ""
}

variable "model_reasoning_effort" {
  type        = string
  description = "The reasoning effort for the model. One of: none, minimal, low, medium, high, xhigh. See https://platform.openai.com/docs/guides/latest-model#lower-reasoning-effort"
  default     = ""
  validation {
    condition     = contains(["", "none", "minimal", "low", "medium", "high", "xhigh"], var.model_reasoning_effort)
    error_message = "model_reasoning_effort must be one of: none, minimal, low, medium, high, xhigh."
  }
}

variable "enable_ai_gateway" {
  type        = bool
  description = "Use AI Gateway for Codex. https://coder.com/docs/ai-coder/ai-gateway"
  default     = false

  validation {
    condition     = !(var.enable_ai_gateway && length(var.openai_api_key) > 0)
    error_message = "openai_api_key cannot be provided when enable_ai_gateway is true. AI Gateway automatically authenticates the client using Coder credentials."
  }
}

resource "coder_env" "openai_api_key" {
  count    = var.openai_api_key != "" ? 1 : 0
  agent_id = var.agent_id
  name     = "OPENAI_API_KEY"
  value    = var.openai_api_key
}

# Authenticates the client against Coder's AI Gateway using the workspace
# owner's session token. Referenced by config.toml model_providers.aigateway.
resource "coder_env" "ai_gateway_session_token" {
  count    = var.enable_ai_gateway ? 1 : 0
  agent_id = var.agent_id
  name     = "CODER_AIBRIDGE_SESSION_TOKEN"
  value    = data.coder_workspace_owner.me.session_token
}

locals {
  workdir         = var.workdir != null ? trimsuffix(var.workdir, "/") : ""
  aibridge_config = <<-EOF
  [model_providers.aigateway]
  name = "AI Gateway"
  base_url = "${data.coder_workspace.me.access_url}/api/v2/aibridge/openai/v1"
  env_key = "CODER_AIBRIDGE_SESSION_TOKEN"
  wire_api = "responses"

  EOF
  install_script = templatefile("${path.module}/scripts/install.sh.tftpl", {
    ARG_INSTALL                = tostring(var.install_codex)
    ARG_CODEX_VERSION          = var.codex_version != "" ? base64encode(var.codex_version) : ""
    ARG_WORKDIR                = local.workdir != "" ? base64encode(local.workdir) : ""
    ARG_BASE_CONFIG_TOML       = var.base_config_toml != "" ? base64encode(var.base_config_toml) : ""
    ARG_MCP                    = var.mcp != "" ? base64encode(var.mcp) : ""
    ARG_ENABLE_AI_GATEWAY      = tostring(var.enable_ai_gateway)
    ARG_AIBRIDGE_CONFIG        = var.enable_ai_gateway ? base64encode(local.aibridge_config) : ""
    ARG_MODEL_REASONING_EFFORT = var.model_reasoning_effort
    ARG_OPENAI_API_KEY         = var.openai_api_key != "" ? base64encode(var.openai_api_key) : ""
  })
  module_dir_name = ".coder-modules/coder-labs/codex"
}

module "coder_utils" {
  source  = "registry.coder.com/coder/coder-utils/coder"
  version = "0.0.1"

  agent_id            = var.agent_id
  module_directory    = "$HOME/${local.module_dir_name}"
  display_name_prefix = "Codex"
  icon                = var.icon
  pre_install_script  = var.pre_install_script
  post_install_script = var.post_install_script
  install_script      = local.install_script
}

output "scripts" {
  description = "Ordered list of coder exp sync names for the coder_script resources this module creates, in run order (pre_install, install, post_install). Scripts that were not configured are absent from the list."
  value       = module.coder_utils.scripts
}
