defmodule Towerops.Gaiia.Webhooks do
  @moduledoc """
  Processes webhook events from Gaiia.

  Handles incremental updates for accounts, billing subscriptions,
  and inventory items. Unknown events are logged and ignored for
  forward-compatibility.
  """

  alias Towerops.Gaiia

  require Logger

  @doc """
  Verify an HMAC-SHA256 signature against the raw request body.

  Returns `true` if the signature matches, `false` otherwise.
  Uses constant-time comparison to prevent timing attacks.
  """
  @spec verify_signature(binary(), binary(), binary()) :: boolean()
  def verify_signature(body, signature, secret) do
    expected = :hmac |> :crypto.mac(:sha256, secret, body) |> Base.encode16(case: :lower)
    Plug.Crypto.secure_compare(expected, signature)
  end

  @doc """
  Process a webhook event from Gaiia.

  Returns `:ok` for all events, including unknown ones (forward-compatible).
  """
  @spec process_event(String.t(), String.t(), map()) :: :ok
  def process_event(organization_id, event, payload) do
    case event do
      "account." <> _ -> handle_account_event(organization_id, event, payload)
      "billing_subscription." <> _ -> handle_subscription_event(organization_id, event, payload)
      "inventory_item." <> _ -> handle_inventory_event(organization_id, event, payload)
      _ -> Logger.info("Ignoring unknown Gaiia webhook event: #{event}")
    end

    :ok
  end

  defp handle_account_event(organization_id, event, %{"data" => data}) do
    gaiia_id = data["id"]

    case event do
      "account.deleted" ->
        upsert_account(organization_id, gaiia_id, data, %{status: "deleted"})

      _ ->
        upsert_account(organization_id, gaiia_id, data, %{})
    end
  end

  defp handle_subscription_event(organization_id, _event, %{"data" => data}) do
    attrs = %{
      gaiia_id: data["id"],
      account_gaiia_id: data["account_id"],
      status: data["status"],
      product_name: data["product_name"],
      mrr_amount: parse_decimal(data["mrr_amount"]),
      currency: data["currency"]
    }

    Gaiia.upsert_billing_subscription(organization_id, drop_nils(attrs))
  end

  defp handle_inventory_event(organization_id, _event, %{"data" => data}) do
    attrs = %{
      gaiia_id: data["id"],
      name: data["name"],
      ip_address: data["ip_address"],
      assigned_account_gaiia_id: data["assigned_account_id"],
      assigned_network_site_gaiia_id: data["assigned_network_site_id"]
    }

    Gaiia.upsert_inventory_item(organization_id, drop_nils(attrs))
  end

  defp upsert_account(organization_id, gaiia_id, data, overrides) do
    attrs =
      %{
        gaiia_id: gaiia_id,
        readable_id: data["readable_id"],
        name: data["name"],
        status: data["status"],
        account_type: data["account_type"],
        address: data["address"]
      }
      |> Map.merge(overrides)
      |> drop_nils()

    Gaiia.upsert_account(organization_id, attrs)
  end

  defp parse_decimal(nil), do: nil
  defp parse_decimal(val) when is_binary(val), do: Decimal.new(val)
  defp parse_decimal(val) when is_number(val), do: Decimal.from_float(val / 1)

  defp drop_nils(map) do
    map
    |> Enum.reject(fn {_k, v} -> is_nil(v) end)
    |> Map.new()
  end
end
