import Config

# config/runtime.exs is executed for all environments, including
# during releases. It is executed after compilation and before the
# system starts, so it is typically used to load production configuration
# and secrets from environment variables or elsewhere. Do not define
# any compile-time configuration in here, as it won't be applied.
# The block below contains prod specific runtime configuration.

# Helper function to read environment variables with Docker secrets support.
# Supports the _FILE suffix pattern: if VAR_FILE is set, reads the value from
# that file path. Otherwise falls back to VAR directly.
# VAR_FILE takes priority and must contain the full absolute path to the secret file.
get_env_or_file = fn var_name, default ->
  file_var = "#{var_name}_FILE"

  case System.get_env(file_var) do
    nil ->
      System.get_env(var_name, default)

    file_path ->
      case File.read(file_path) do
        {:ok, content} ->
          String.trim_trailing(content)

        {:error, reason} ->
          raise """
          Failed to read secret from file specified in #{file_var}="#{file_path}".
          Error: #{inspect(reason)}
          """
      end
  end
end

# Same as get_env_or_file but raises if the value is not set
get_env_or_file! = fn var_name, error_message ->
  case get_env_or_file.(var_name, nil) do
    nil -> raise error_message
    value -> value
  end
end

# Build database URL from individual components or use DATABASE_URL directly.
# Supports both approaches:
# 1. DATABASE_URL (or DATABASE_URL_FILE) - full connection URL
# 2. Separate vars: DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD (or _FILE), DATABASE_NAME, DATABASE_PORT
build_database_url = fn ->
  case get_env_or_file.("DATABASE_URL", nil) do
    nil ->
      # Build URL from separate components
      host =
        System.get_env("DATABASE_HOST") ||
          raise "DATABASE_HOST is required when DATABASE_URL is not set"

      user =
        System.get_env("DATABASE_USER") ||
          raise "DATABASE_USER is required when DATABASE_URL is not set"

      password =
        get_env_or_file!.("DATABASE_PASSWORD", """
        DATABASE_PASSWORD or DATABASE_PASSWORD_FILE is required when DATABASE_URL is not set.
        """)

      database =
        System.get_env("DATABASE_NAME") ||
          raise "DATABASE_NAME is required when DATABASE_URL is not set"

      port = System.get_env("DATABASE_PORT", "5432")

      # URL-encode the password to handle special characters
      encoded_password = URI.encode_www_form(password)
      "ecto://#{user}:#{encoded_password}@#{host}:#{port}/#{database}"

    url ->
      url
  end
end

# ## Using releases
#
# If you use `mix release`, you need to explicitly enable the server
# by passing the PHX_SERVER=true when you start it:
#
#     PHX_SERVER=true bin/mv start
#
# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server`
# script that automatically sets the env var above.
if System.get_env("PHX_SERVER") do
  config :mv, MvWeb.Endpoint, server: true
end

# OIDC group → Admin role sync: read from ENV in all environments (dev/test/prod)
config :mv, :oidc_role_sync,
  admin_group_name: System.get_env("OIDC_ADMIN_GROUP_NAME"),
  groups_claim: System.get_env("OIDC_GROUPS_CLAIM") || "groups"

if config_env() == :prod do
  database_url = build_database_url.()

  maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []

  config :mv, Mv.Repo,
    # ssl: true,
    url: database_url,
    pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
    socket_options: maybe_ipv6

  # The secret key base is used to sign/encrypt cookies and other secrets.
  # A default value is used in config/dev.exs and config/test.exs but you
  # want to use a different value for prod and you most likely don't want
  # to check this value into version control, so we use an environment
  # variable instead.
  # Supports SECRET_KEY_BASE or SECRET_KEY_BASE_FILE for Docker secrets.
  secret_key_base =
    get_env_or_file!.("SECRET_KEY_BASE", """
    environment variable SECRET_KEY_BASE (or SECRET_KEY_BASE_FILE) is missing.
    You can generate one by calling: mix phx.gen.secret
    """)

  # PHX_HOST or DOMAIN can be used to set the host for the application.
  # DOMAIN is commonly used in deployment environments (e.g., Portainer templates).
  host =
    System.get_env("PHX_HOST") ||
      System.get_env("DOMAIN") ||
      raise "Please define the PHX_HOST or DOMAIN environment variable."

  port = String.to_integer(System.get_env("PORT") || "4000")

  config :mv, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")

  # OIDC configuration (works with any OIDC provider: Authentik, Rauthy, Keycloak, etc.)
  # The redirect_uri callback path is /auth/user/oidc/callback.
  #
  # Supports OIDC_CLIENT_SECRET or OIDC_CLIENT_SECRET_FILE for Docker secrets.
  # OIDC_CLIENT_SECRET is required only if OIDC is being used (indicated by explicit OIDC env vars).
  oidc_base_url = System.get_env("OIDC_BASE_URL")
  oidc_client_id = System.get_env("OIDC_CLIENT_ID")
  oidc_in_use = not is_nil(oidc_base_url) or not is_nil(oidc_client_id)

  client_secret =
    if oidc_in_use do
      get_env_or_file!.("OIDC_CLIENT_SECRET", """
      environment variable OIDC_CLIENT_SECRET (or OIDC_CLIENT_SECRET_FILE) is missing.
      This is required when OIDC authentication is configured (OIDC_BASE_URL or OIDC_CLIENT_ID is set).
      """)
    else
      get_env_or_file.("OIDC_CLIENT_SECRET", nil)
    end

  # Build redirect_uri: use OIDC_REDIRECT_URI if set, otherwise build from host.
  # Uses HTTPS since production runs behind TLS termination.
  default_redirect_uri = "https://#{host}/auth/user/oidc/callback"

  config :mv, :oidc,
    client_id: oidc_client_id || "mv",
    base_url: oidc_base_url || "http://localhost:8080/auth/v1",
    client_secret: client_secret,
    redirect_uri: System.get_env("OIDC_REDIRECT_URI") || default_redirect_uri

  # Token signing secret from environment variable
  # This overrides the placeholder value set in prod.exs
  # Supports TOKEN_SIGNING_SECRET or TOKEN_SIGNING_SECRET_FILE for Docker secrets.
  token_signing_secret =
    get_env_or_file!.("TOKEN_SIGNING_SECRET", """
    environment variable TOKEN_SIGNING_SECRET (or TOKEN_SIGNING_SECRET_FILE) is missing.
    You can generate one by calling: mix phx.gen.secret
    """)

  config :mv, :token_signing_secret, token_signing_secret

  config :mv, MvWeb.Endpoint,
    url: [host: host, port: 443, scheme: "https"],
    http: [
      # Bind on all IPv4 interfaces.
      # Use {0, 0, 0, 0, 0, 0, 0, 0} for IPv6, or {127, 0, 0, 1} for localhost only.
      # See the documentation on https://hexdocs.pm/bandit/Bandit.html#t:options/0
      ip: {0, 0, 0, 0},
      port: port
    ],
    secret_key_base: secret_key_base,
    # Allow connections from localhost and 127.0.0.1
    check_origin: [
      "//#{host}",
      "//localhost:#{port}",
      "//127.0.0.1:#{port}"
    ]

  # ## SSL Support
  #
  # To get SSL working, you will need to add the `https` key
  # to your endpoint configuration:
  #
  #     config :mv, MvWeb.Endpoint,
  #       https: [
  #         ...,
  #         port: 443,
  #         cipher_suite: :strong,
  #         keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
  #         certfile: System.get_env("SOME_APP_SSL_CERT_PATH")
  #       ]
  #
  # The `cipher_suite` is set to `:strong` to support only the
  # latest and more secure SSL ciphers. This means old browsers
  # and clients may not be supported. You can set it to
  # `:compatible` for wider support.
  #
  # `:keyfile` and `:certfile` expect an absolute path to the key
  # and cert in disk or a relative path inside priv, for example
  # "priv/ssl/server.key". For all supported SSL configuration
  # options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
  #
  # We also recommend setting `force_ssl` in your config/prod.exs,
  # ensuring no data is ever sent via http, always redirecting to https:
  #
  #     config :mv, MvWeb.Endpoint,
  #       force_ssl: [hsts: true]
  #
  # Check `Plug.SSL` for all available options in `force_ssl`.

  # ## Configuring the mailer
  #
  # In production you need to configure the mailer to use a different adapter.
  # Also, you may need to configure the Swoosh API client of your choice if you
  # are not using SMTP. Here is an example of the configuration:
  #
  #     config :mv, Mv.Mailer,
  #       adapter: Swoosh.Adapters.Mailgun,
  #       api_key: System.get_env("MAILGUN_API_KEY"),
  #       domain: System.get_env("MAILGUN_DOMAIN")
  #
  # For this example you need include a HTTP client required by Swoosh API client.
  # Swoosh supports Hackney, Req and Finch out of the box:
  #
  #     config :swoosh, :api_client, Swoosh.ApiClient.Hackney
  #
  # See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details.
end
