defmodule Towerops.Gaiia.WebhooksTest do
  use Towerops.DataCase, async: true

  import Towerops.AccountsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Gaiia
  alias Towerops.Gaiia.Webhooks

  setup do
    user = user_fixture()
    org = organization_fixture(user.id)
    %{org: org}
  end

  describe "process_event/3 - account events" do
    test "account.created inserts a new account", %{org: org} do
      payload = %{
        "entity_id" => "gaiia-acct-1",
        "data" => %{
          "id" => "gaiia-acct-1",
          "readable_id" => "ACCT-001",
          "name" => "John Smith",
          "status" => "active",
          "account_type" => "residential"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "account.created", payload)
      assert account = Gaiia.get_account(org.id, "gaiia-acct-1")
      assert account.name == "John Smith"
      assert account.status == "active"
    end

    test "account.status_updated updates existing account status", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_account(org.id, %{
          gaiia_id: "gaiia-acct-1",
          name: "John Smith",
          status: "active"
        })

      payload = %{
        "entity_id" => "gaiia-acct-1",
        "data" => %{
          "id" => "gaiia-acct-1",
          "name" => "John Smith",
          "status" => "suspended"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "account.status_updated", payload)
      assert account = Gaiia.get_account(org.id, "gaiia-acct-1")
      assert account.status == "suspended"
    end

    test "account.physical_address_updated updates address", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_account(org.id, %{
          gaiia_id: "gaiia-acct-1",
          name: "John Smith",
          status: "active"
        })

      payload = %{
        "entity_id" => "gaiia-acct-1",
        "data" => %{
          "id" => "gaiia-acct-1",
          "name" => "John Smith",
          "status" => "active",
          "address" => %{
            "street" => "123 Main St",
            "city" => "Springfield"
          }
        }
      }

      assert :ok = Webhooks.process_event(org.id, "account.physical_address_updated", payload)
      assert account = Gaiia.get_account(org.id, "gaiia-acct-1")
      assert account.address["street"] == "123 Main St"
    end

    test "account.deleted removes or marks account inactive", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_account(org.id, %{
          gaiia_id: "gaiia-acct-1",
          name: "John Smith",
          status: "active"
        })

      payload = %{
        "entity_id" => "gaiia-acct-1",
        "data" => %{"id" => "gaiia-acct-1"}
      }

      assert :ok = Webhooks.process_event(org.id, "account.deleted", payload)
      assert account = Gaiia.get_account(org.id, "gaiia-acct-1")
      assert account.status == "deleted"
    end
  end

  describe "process_event/3 - billing subscription events" do
    test "billing_subscription.activated upserts subscription", %{org: org} do
      payload = %{
        "entity_id" => "gaiia-sub-1",
        "data" => %{
          "id" => "gaiia-sub-1",
          "account_id" => "gaiia-acct-1",
          "status" => "active",
          "product_name" => "100 Mbps Plan",
          "mrr_amount" => "79.99",
          "currency" => "USD"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "billing_subscription.activated", payload)
      assert sub = Gaiia.get_billing_subscription(org.id, "gaiia-sub-1")
      assert sub.status == "active"
      assert sub.product_name == "100 Mbps Plan"
      assert Decimal.equal?(sub.mrr_amount, Decimal.new("79.99"))
    end

    test "billing_subscription.suspended updates status", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_billing_subscription(org.id, %{
          gaiia_id: "gaiia-sub-1",
          account_gaiia_id: "gaiia-acct-1",
          status: "active",
          product_name: "100 Mbps Plan"
        })

      payload = %{
        "entity_id" => "gaiia-sub-1",
        "data" => %{
          "id" => "gaiia-sub-1",
          "account_id" => "gaiia-acct-1",
          "status" => "suspended",
          "product_name" => "100 Mbps Plan"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "billing_subscription.suspended", payload)
      assert sub = Gaiia.get_billing_subscription(org.id, "gaiia-sub-1")
      assert sub.status == "suspended"
    end

    test "billing_subscription.unassigned updates status", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_billing_subscription(org.id, %{
          gaiia_id: "gaiia-sub-1",
          account_gaiia_id: "gaiia-acct-1",
          status: "active",
          product_name: "100 Mbps Plan"
        })

      payload = %{
        "entity_id" => "gaiia-sub-1",
        "data" => %{
          "id" => "gaiia-sub-1",
          "account_id" => "gaiia-acct-1",
          "status" => "unassigned",
          "product_name" => "100 Mbps Plan"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "billing_subscription.unassigned", payload)
      assert sub = Gaiia.get_billing_subscription(org.id, "gaiia-sub-1")
      assert sub.status == "unassigned"
    end
  end

  describe "process_event/3 - inventory item events" do
    test "inventory_item.assigned updates assignment fields", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_inventory_item(org.id, %{
          gaiia_id: "gaiia-inv-1",
          name: "Router Alpha"
        })

      payload = %{
        "entity_id" => "gaiia-inv-1",
        "data" => %{
          "id" => "gaiia-inv-1",
          "name" => "Router Alpha",
          "assigned_account_id" => "gaiia-acct-1",
          "assigned_network_site_id" => "gaiia-site-1"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "inventory_item.assigned", payload)
      assert item = Gaiia.get_inventory_item(org.id, "gaiia-inv-1")
      assert item.assigned_account_gaiia_id == "gaiia-acct-1"
      assert item.assigned_network_site_gaiia_id == "gaiia-site-1"
    end

    test "inventory_item.ip_address_assigned updates IP", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_inventory_item(org.id, %{
          gaiia_id: "gaiia-inv-1",
          name: "Router Alpha"
        })

      payload = %{
        "entity_id" => "gaiia-inv-1",
        "data" => %{
          "id" => "gaiia-inv-1",
          "name" => "Router Alpha",
          "ip_address" => "10.0.0.5"
        }
      }

      assert :ok = Webhooks.process_event(org.id, "inventory_item.ip_address_assigned", payload)
      assert item = Gaiia.get_inventory_item(org.id, "gaiia-inv-1")
      assert item.ip_address == "10.0.0.5"
    end

    test "inventory_item.ip_address_unassigned clears IP", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_inventory_item(org.id, %{
          gaiia_id: "gaiia-inv-1",
          name: "Router Alpha",
          ip_address: "10.0.0.5"
        })

      payload = %{
        "entity_id" => "gaiia-inv-1",
        "data" => %{
          "id" => "gaiia-inv-1",
          "name" => "Router Alpha",
          "ip_address" => nil
        }
      }

      assert :ok =
               Webhooks.process_event(org.id, "inventory_item.ip_address_unassigned", payload)

      assert item = Gaiia.get_inventory_item(org.id, "gaiia-inv-1")
      assert is_nil(item.ip_address)
    end
  end

  describe "process_event/3 - unknown events" do
    test "unknown events are ignored gracefully", %{org: org} do
      payload = %{"entity_id" => "whatever", "data" => %{}}
      assert :ok = Webhooks.process_event(org.id, "some.unknown.event", payload)
    end
  end

  describe "verify_signature/2" do
    test "returns true for valid HMAC-SHA256 signature" do
      secret = "test-webhook-secret"
      body = ~s({"event":"account.created"})
      signature = :hmac |> :crypto.mac(:sha256, secret, body) |> Base.encode16(case: :lower)

      assert Webhooks.verify_signature(body, signature, secret) == true
    end

    test "returns false for invalid signature" do
      secret = "test-webhook-secret"
      body = ~s({"event":"account.created"})

      assert Webhooks.verify_signature(body, "invalid-signature", secret) == false
    end

    test "returns false for tampered body" do
      secret = "test-webhook-secret"
      body = ~s({"event":"account.created"})
      signature = :hmac |> :crypto.mac(:sha256, secret, body) |> Base.encode16(case: :lower)
      tampered_body = ~s({"event":"account.deleted"})

      assert Webhooks.verify_signature(tampered_body, signature, secret) == false
    end
  end
end
