defmodule Towerops.SitesTest do
  use Towerops.DataCase

  alias Towerops.Sites

  describe "sites" do
    import Towerops.AccountsFixtures

    alias Towerops.Sites.Site

    setup do
      user = user_fixture()
      {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
      %{organization: organization, user: user}
    end

    @valid_attrs %{name: "Test Site", location: "New York", description: "A test site"}
    @update_attrs %{name: "Updated Site", location: "Boston", description: "Updated desc"}
    @invalid_attrs %{name: nil}

    test "list_organization_sites/1 returns all sites for an organization", %{
      organization: organization
    } do
      {:ok, site} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))
      result = Sites.list_organization_sites(organization.id)
      assert length(result) == 1
      assert hd(result).id == site.id
    end

    test "list_root_sites/1 returns only root sites without parents", %{organization: organization} do
      {:ok, root1} =
        Sites.create_site(%{name: "Root 1", organization_id: organization.id})

      {:ok, root2} =
        Sites.create_site(%{name: "Root 2", organization_id: organization.id})

      {:ok, _child} =
        Sites.create_site(%{
          name: "Child",
          organization_id: organization.id,
          parent_site_id: root1.id
        })

      roots = Sites.list_root_sites(organization.id)
      assert length(roots) == 2
      assert Enum.any?(roots, &(&1.id == root1.id))
      assert Enum.any?(roots, &(&1.id == root2.id))
    end

    test "list_child_sites/1 returns child sites for a parent", %{organization: organization} do
      {:ok, parent} = Sites.create_site(%{name: "Parent", organization_id: organization.id})

      {:ok, child1} =
        Sites.create_site(%{
          name: "Child 1",
          organization_id: organization.id,
          parent_site_id: parent.id
        })

      {:ok, child2} =
        Sites.create_site(%{
          name: "Child 2",
          organization_id: organization.id,
          parent_site_id: parent.id
        })

      children = Sites.list_child_sites(parent.id)
      assert length(children) == 2
      assert Enum.any?(children, &(&1.id == child1.id))
      assert Enum.any?(children, &(&1.id == child2.id))
    end

    test "list_child_sites/1 returns empty list when no children exist", %{
      organization: organization
    } do
      {:ok, parent} = Sites.create_site(%{name: "Parent", organization_id: organization.id})
      assert Sites.list_child_sites(parent.id) == []
    end

    test "get_site!/1 returns the site with preloads", %{organization: organization} do
      {:ok, parent} = Sites.create_site(%{name: "Parent", organization_id: organization.id})

      {:ok, child} =
        Sites.create_site(%{
          name: "Child",
          organization_id: organization.id,
          parent_site_id: parent.id
        })

      retrieved_parent = Sites.get_site!(parent.id)
      assert retrieved_parent.id == parent.id
      assert Ecto.assoc_loaded?(retrieved_parent.child_sites)
      assert length(retrieved_parent.child_sites) == 1

      retrieved_child = Sites.get_site!(child.id)
      assert retrieved_child.id == child.id
      assert Ecto.assoc_loaded?(retrieved_child.parent_site)
      assert retrieved_child.parent_site.id == parent.id
    end

    test "get_organization_site!/2 returns the site with given id", %{organization: organization} do
      {:ok, site} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))

      assert Sites.get_organization_site!(organization.id, site.id).id == site.id
    end

    test "create_site/1 with valid data creates a site", %{organization: organization} do
      attrs = Map.put(@valid_attrs, :organization_id, organization.id)
      assert {:ok, %Site{} = site} = Sites.create_site(attrs)
      assert site.name == "Test Site"
      assert site.location == "New York"
      assert site.description == "A test site"
    end

    test "create_site/1 with parent_site_id creates hierarchical site", %{
      organization: organization
    } do
      {:ok, parent} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))

      attrs =
        @valid_attrs
        |> Map.put(:organization_id, organization.id)
        |> Map.put(:parent_site_id, parent.id)
        |> Map.put(:name, "Child Site")

      assert {:ok, %Site{} = child} = Sites.create_site(attrs)
      assert child.parent_site_id == parent.id
    end

    test "create_site/1 with invalid data returns error changeset" do
      assert {:error, %Ecto.Changeset{}} = Sites.create_site(@invalid_attrs)
    end

    test "update_site/2 with valid data updates the site", %{organization: organization} do
      {:ok, site} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))
      assert {:ok, %Site{} = site} = Sites.update_site(site, @update_attrs)
      assert site.name == "Updated Site"
      assert site.location == "Boston"
    end

    test "update_site/2 with invalid data returns error changeset", %{organization: organization} do
      {:ok, site} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))
      assert {:error, %Ecto.Changeset{}} = Sites.update_site(site, @invalid_attrs)

      assert Sites.get_organization_site!(organization.id, site.id).name == site.name
    end

    test "delete_site/1 deletes the site", %{organization: organization} do
      {:ok, site} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))
      assert {:ok, %Site{}} = Sites.delete_site(site)

      assert_raise Ecto.NoResultsError, fn ->
        Sites.get_organization_site!(organization.id, site.id)
      end
    end

    test "change_site/1 returns a site changeset", %{organization: organization} do
      {:ok, site} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))
      assert %Ecto.Changeset{} = Sites.change_site(site)
    end

    test "build_site_tree/1 builds hierarchical tree structure", %{organization: organization} do
      {:ok, parent} = Sites.create_site(Map.put(@valid_attrs, :organization_id, organization.id))

      {:ok, _child1} =
        Sites.create_site(%{
          name: "Child 1",
          organization_id: organization.id,
          parent_site_id: parent.id
        })

      {:ok, _child2} =
        Sites.create_site(%{
          name: "Child 2",
          organization_id: organization.id,
          parent_site_id: parent.id
        })

      tree = Sites.build_site_tree(organization.id)
      assert length(tree) == 1
      [root] = tree
      assert length(root.children) == 2
    end
  end
end
