defmodule Towerops.GaiiaTest do
  use Towerops.DataCase, async: true

  import Towerops.AccountsFixtures
  import Towerops.DevicesFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Gaiia

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

  describe "accounts" do
    test "upsert_account/2 creates a new account", %{org: org} do
      attrs = %{gaiia_id: "acct-1", name: "Alice", status: "Active"}
      assert {:ok, account} = Gaiia.upsert_account(org.id, attrs)
      assert account.gaiia_id == "acct-1"
      assert account.name == "Alice"
    end

    test "upsert_account/2 updates existing account", %{org: org} do
      attrs = %{gaiia_id: "acct-1", name: "Alice"}
      {:ok, _} = Gaiia.upsert_account(org.id, attrs)
      {:ok, updated} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-1", name: "Alice Smith"})
      assert updated.name == "Alice Smith"
      assert length(Gaiia.list_accounts(org.id)) == 1
    end

    test "list_accounts/1 returns accounts for organization", %{org: org} do
      {:ok, _} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-1", name: "Alice"})
      {:ok, _} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-2", name: "Bob"})
      assert length(Gaiia.list_accounts(org.id)) == 2
    end

    test "get_account/2 returns account by gaiia_id", %{org: org} do
      {:ok, _} = Gaiia.upsert_account(org.id, %{gaiia_id: "acct-1", name: "Alice"})
      assert %{name: "Alice"} = Gaiia.get_account(org.id, "acct-1")
      assert is_nil(Gaiia.get_account(org.id, "nonexistent"))
    end
  end

  describe "network_sites" do
    test "upsert_network_site/2 creates a new site", %{org: org} do
      attrs = %{gaiia_id: "site-1", name: "Tower 3", ip_blocks: ["10.0.0.0/24"]}
      assert {:ok, site} = Gaiia.upsert_network_site(org.id, attrs)
      assert site.gaiia_id == "site-1"
      assert site.ip_blocks == ["10.0.0.0/24"]
    end

    test "upsert_network_site/2 preserves site_id mapping on update", %{org: org} do
      {:ok, site} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "site-1", name: "Tower 3"})
      assert is_nil(site.site_id)

      # Simulate user mapping
      towerops_site = create_site(org.id)
      Gaiia.update_network_site_mapping(site, %{site_id: towerops_site.id})

      # Re-sync should preserve mapping
      {:ok, updated} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "site-1", name: "Tower 3 Updated"})
      assert updated.name == "Tower 3 Updated"
      assert updated.site_id == towerops_site.id
    end

    test "list_network_sites/1 returns sites for organization", %{org: org} do
      {:ok, _} = Gaiia.upsert_network_site(org.id, %{gaiia_id: "site-1", name: "Tower 1"})
      assert length(Gaiia.list_network_sites(org.id)) == 1
    end
  end

  describe "inventory_items" do
    test "upsert_inventory_item/2 creates a new item", %{org: org} do
      attrs = %{gaiia_id: "item-1", name: "AF5XHD", serial_number: "SN123"}
      assert {:ok, item} = Gaiia.upsert_inventory_item(org.id, attrs)
      assert item.serial_number == "SN123"
    end

    test "upsert_inventory_item/2 preserves device_id mapping on update", %{org: org} do
      {:ok, item} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "AF5XHD"})
      assert is_nil(item.device_id)

      device = device_fixture(%{organization_id: org.id})
      Gaiia.update_inventory_item_mapping(item, %{device_id: device.id})

      {:ok, updated} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "AF5XHD v2"})
      assert updated.name == "AF5XHD v2"
      assert updated.device_id == device.id
    end

    test "list_inventory_items/1 returns items for organization", %{org: org} do
      {:ok, _} = Gaiia.upsert_inventory_item(org.id, %{gaiia_id: "item-1", name: "AF5XHD"})
      assert length(Gaiia.list_inventory_items(org.id)) == 1
    end
  end

  describe "billing_subscriptions" do
    test "upsert_billing_subscription/2 creates a new subscription", %{org: org} do
      attrs = %{gaiia_id: "sub-1", account_gaiia_id: "acct-1", product_name: "100Mbps"}
      assert {:ok, sub} = Gaiia.upsert_billing_subscription(org.id, attrs)
      assert sub.product_name == "100Mbps"
    end

    test "list_billing_subscriptions_for_account/2 filters by account", %{org: org} do
      {:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-1", account_gaiia_id: "acct-1"})
      {:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-2", account_gaiia_id: "acct-2"})

      assert length(Gaiia.list_billing_subscriptions_for_account(org.id, "acct-1")) == 1
    end

    test "list_billing_subscriptions/1 returns all subscriptions", %{org: org} do
      {:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-1"})
      {:ok, _} = Gaiia.upsert_billing_subscription(org.id, %{gaiia_id: "sub-2"})
      assert length(Gaiia.list_billing_subscriptions(org.id)) == 2
    end
  end

  defp create_site(organization_id) do
    {:ok, site} =
      Towerops.Sites.create_site(%{
        name: "Test Site #{System.unique_integer([:positive])}",
        organization_id: organization_id
      })

    site
  end

  describe "get_org_subscriber_totals/1" do
    test "returns zero totals when no network sites", %{org: org} do
      assert %{total_subscribers: 0, total_mrr: total_mrr} = Gaiia.get_org_subscriber_totals(org.id)
      assert Decimal.equal?(total_mrr, Decimal.new(0))
    end

    test "sums account_count and total_mrr from network sites", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_network_site(org.id, %{
          gaiia_id: "ns-1",
          name: "Tower A",
          account_count: 50,
          total_mrr: Decimal.new("2500.00")
        })

      {:ok, _} =
        Gaiia.upsert_network_site(org.id, %{
          gaiia_id: "ns-2",
          name: "Tower B",
          account_count: 30,
          total_mrr: Decimal.new("1500.00")
        })

      result = Gaiia.get_org_subscriber_totals(org.id)
      assert result.total_subscribers == 80
      assert Decimal.equal?(result.total_mrr, Decimal.new("4000.00"))
    end

    test "handles nil values gracefully", %{org: org} do
      {:ok, _} =
        Gaiia.upsert_network_site(org.id, %{
          gaiia_id: "ns-nil",
          name: "Tower Nil",
          account_count: nil,
          total_mrr: nil
        })

      result = Gaiia.get_org_subscriber_totals(org.id)
      assert result.total_subscribers == 0
      assert Decimal.equal?(result.total_mrr, Decimal.new(0))
    end
  end

  describe "get_site_subscriber_summary/1" do
    test "returns subscriber data for a mapped site", %{org: org} do
      site = create_site(org.id)

      {:ok, _} =
        Gaiia.upsert_network_site(org.id, %{
          gaiia_id: "ns-mapped",
          name: "Mapped Tower",
          account_count: 42,
          total_mrr: Decimal.new("3100.50"),
          site_id: site.id
        })

      result = Gaiia.get_site_subscriber_summary(site.id)
      assert result.account_count == 42
      assert Decimal.equal?(result.total_mrr, Decimal.new("3100.50"))
    end

    test "returns nil for unmapped site", %{org: org} do
      site = create_site(org.id)
      assert is_nil(Gaiia.get_site_subscriber_summary(site.id))
    end
  end
end
