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

  import Towerops.AccountsFixtures
  import Towerops.IntegrationsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Gaiia
  alias Towerops.Gaiia.Client
  alias Towerops.Gaiia.Sync

  setup do
    user = user_fixture()
    org = organization_fixture(user.id)
    integration = integration_fixture(org.id, %{provider: "gaiia"})
    %{org: org, integration: integration}
  end

  describe "sync_organization/1" do
    test "syncs all entity types", %{integration: integration} do
      stub_all_endpoints()

      assert {:ok, result} = Sync.sync_organization(integration)
      assert result.accounts == 1
      assert result.network_sites == 1
      assert result.inventory_items == 1
      assert result.subscriptions == 1

      updated = Repo.reload!(integration)
      assert updated.last_sync_status == "success"
      assert updated.last_synced_at
    end

    test "maps account fields correctly", %{org: org, integration: integration} do
      stub_all_endpoints()

      {:ok, _} = Sync.sync_organization(integration)

      [account] = Gaiia.list_accounts(org.id)
      assert account.gaiia_id == "acct-1"
      assert account.readable_id == "1001"
      assert account.name == "Alice Smith"
      assert account.status == "Active"
      assert account.account_type == "Residential"
      assert account.subscription_count == 1
      assert account.address["city"] == "Portland"
    end

    test "maps network site fields correctly", %{org: org, integration: integration} do
      stub_all_endpoints()

      {:ok, _} = Sync.sync_organization(integration)

      [site] = Gaiia.list_network_sites(org.id)
      assert site.gaiia_id == "site-1"
      assert site.name == "Tower 3"
      assert site.ip_blocks == ["10.0.0.0/24"]
    end

    test "maps inventory item fields correctly", %{org: org, integration: integration} do
      stub_all_endpoints()

      {:ok, _} = Sync.sync_organization(integration)

      [item] = Gaiia.list_inventory_items(org.id)
      assert item.gaiia_id == "item-1"
      assert item.name == "airFiber 5XHD"
      assert item.model_name == "airFiber 5XHD"
      assert item.manufacturer_name == "Ubiquiti"
      assert item.category == "AP"
      assert item.assigned_account_gaiia_id == "acct-1"
    end

    test "maps billing subscription fields correctly", %{org: org, integration: integration} do
      stub_all_endpoints()

      {:ok, _} = Sync.sync_organization(integration)

      [sub] = Gaiia.list_billing_subscriptions(org.id)
      assert sub.gaiia_id == "sub-1"
      assert sub.account_gaiia_id == "acct-1"
      assert sub.status == "Active"
      assert sub.product_name == "100Mbps Unlimited"
    end

    test "marks sync as failed on API error", %{integration: integration} do
      Req.Test.stub(Client, fn conn ->
        conn
        |> Plug.Conn.put_status(401)
        |> Req.Test.json(%{"error" => "unauthorized"})
      end)

      assert {:error, :unauthorized} = Sync.sync_organization(integration)

      updated = Repo.reload!(integration)
      assert updated.last_sync_status == "failed"
    end

    test "upserts existing records without duplicating", %{org: org, integration: integration} do
      stub_all_endpoints()

      {:ok, _} = Sync.sync_organization(integration)
      {:ok, _} = Sync.sync_organization(Repo.reload!(integration))

      assert length(Gaiia.list_accounts(org.id)) == 1
      assert length(Gaiia.list_network_sites(org.id)) == 1
      assert length(Gaiia.list_inventory_items(org.id)) == 1
      assert length(Gaiia.list_billing_subscriptions(org.id)) == 1
    end
  end

  defp stub_all_endpoints do
    Req.Test.stub(Client, fn conn ->
      {:ok, body, _conn} = Plug.Conn.read_body(conn)
      decoded = Jason.decode!(body)
      query = decoded["query"]

      response =
        cond do
          String.contains?(query, "ListAccounts") -> accounts_response()
          String.contains?(query, "ListNetworkSites") -> network_sites_response()
          String.contains?(query, "ListInventoryItems") -> inventory_items_response()
          String.contains?(query, "ListBillingSubscriptions") -> billing_subscriptions_response()
          true -> %{"data" => %{}}
        end

      Req.Test.json(conn, response)
    end)
  end

  defp accounts_response do
    %{
      "data" => %{
        "accounts" => %{
          "edges" => [
            %{
              "node" => %{
                "id" => "acct-1",
                "readableId" => "1001",
                "name" => "Alice Smith",
                "status" => %{"id" => "status-1", "name" => "Active", "type" => "ACTIVE"},
                "type" => %{"id" => "type-1", "name" => "Residential"},
                "physicalAddress" => %{
                  "line1" => "123 Main St",
                  "locality" => "Portland",
                  "region" => "OR",
                  "postalCode" => "97201",
                  "country" => "US",
                  "latitude" => 45.5,
                  "longitude" => -122.6
                },
                "billingSubscriptions" => %{
                  "edges" => [
                    %{
                      "node" => %{
                        "id" => "sub-1",
                        "status" => %{"id" => "sub-status-1", "name" => "Active"}
                      }
                    }
                  ]
                }
              }
            }
          ],
          "pageInfo" => %{"hasNextPage" => false, "endCursor" => nil}
        }
      }
    }
  end

  defp network_sites_response do
    %{
      "data" => %{
        "networkSites" => %{
          "edges" => [
            %{
              "node" => %{
                "id" => "site-1",
                "name" => "Tower 3",
                "address" => %{
                  "line1" => "456 Tower Rd",
                  "locality" => "Portland",
                  "region" => "OR",
                  "postalCode" => "97201",
                  "country" => "US",
                  "latitude" => 45.5,
                  "longitude" => -122.6
                },
                "ipBlocks" => %{
                  "edges" => [
                    %{"node" => %{"subnet" => "10.0.0.0/24"}}
                  ]
                }
              }
            }
          ],
          "pageInfo" => %{"hasNextPage" => false, "endCursor" => nil}
        }
      }
    }
  end

  defp inventory_items_response do
    %{
      "data" => %{
        "inventoryItems" => %{
          "edges" => [
            %{
              "node" => %{
                "id" => "item-1",
                "status" => %{"id" => "inv-status-1", "name" => "Active"},
                "ipAddressV4" => "10.0.0.1",
                "model" => %{
                  "name" => "airFiber 5XHD",
                  "manufacturer" => %{"name" => "Ubiquiti"},
                  "category" => %{"name" => "AP"}
                },
                "assignation" => %{
                  "assigneeType" => "Account",
                  "assignee" => %{"id" => "acct-1"}
                }
              }
            }
          ],
          "pageInfo" => %{"hasNextPage" => false, "endCursor" => nil}
        }
      }
    }
  end

  defp billing_subscriptions_response do
    %{
      "data" => %{
        "billingSubscriptions" => %{
          "edges" => [
            %{
              "node" => %{
                "id" => "sub-1",
                "status" => %{"id" => "sub-status-1", "name" => "Active"},
                "productVersion" => %{
                  "product" => %{"name" => "100Mbps Unlimited"},
                  "price" => 7999,
                  "currency" => "USD"
                },
                "entity" => %{"id" => "acct-1"}
              }
            }
          ],
          "pageInfo" => %{"hasNextPage" => false, "endCursor" => nil}
        }
      }
    }
  end
end
