defmodule ToweropsWeb.PlugExceptions do
  @moduledoc """
  Protocol implementations for converting expected Phoenix exceptions
  into clean HTTP status codes rather than raising errors.

  This reduces noise in error tracking by treating invalid requests
  (wrong MIME types, invalid CSRF tokens) as bad requests rather than
  application failures.

  ## Rationale

  Production applications receive noise from legitimate bad requests:
  - API clients sending incorrect Accept headers
  - Mobile apps with stale CSRF tokens after backgrounding
  - Automation tools (Terraform, scripts) with malformed requests

  These are client errors (400-level), not server failures (500-level).
  By implementing `Plug.Exception` protocol for these exceptions, we:

  1. Return clean HTTP 400 Bad Request responses
  2. Reduce exception tracking alerts for expected client errors
  3. Keep error logs focused on genuine application failures

  ## Implementation

  Each exception type gets a protocol implementation with two callbacks:

  - `status/1` - Returns the HTTP status code (400 for bad requests)
  - `actions/1` - Returns suggested actions (empty list for now)

  ## Covered Exception Types

  - `Phoenix.NotAcceptableError` - Invalid Accept headers from API clients
  - `Plug.CSRFProtection.InvalidCSRFTokenError` - Stale or invalid CSRF tokens

  ## Monitoring

  These exceptions are still logged at debug level, allowing monitoring
  without triggering production alerts. If you see patterns indicating
  attacks (e.g., excessive CSRF failures), investigate via logs.

  ## See Also

  - Documentation: `docs/exception_handling.md`
  - Tests: `test/towerops_web/plug_exceptions_test.exs`
  """

  require Logger

  # Invalid Accept headers from API consumers (automation, mobile apps, etc.)
  defimpl Plug.Exception, for: Phoenix.NotAcceptableError do
    def status(exception) do
      Logger.debug("Converting Phoenix.NotAcceptableError to 400: #{inspect(exception)}")
      400
    end

    def actions(_exception), do: []
  end

  # Stale CSRF tokens from mobile app or browser sessions
  defimpl Plug.Exception, for: Plug.CSRFProtection.InvalidCSRFTokenError do
    def status(exception) do
      Logger.debug("Converting InvalidCSRFTokenError to 400: #{inspect(exception)}")
      400
    end

    def actions(_exception), do: []
  end
end
