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

  import Towerops.AccountsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Integrations
  alias Towerops.Integrations.Integration

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

  describe "list_integrations/1" do
    test "returns all integrations for an organization", %{organization: org} do
      {:ok, _} = Integrations.create_integration(org.id, %{provider: "preseem"})
      integrations = Integrations.list_integrations(org.id)
      assert length(integrations) == 1
    end

    test "does not return integrations from other orgs", %{organization: org} do
      user2 = user_fixture()
      org2 = organization_fixture(user2.id)
      {:ok, _} = Integrations.create_integration(org2.id, %{provider: "preseem"})
      assert Integrations.list_integrations(org.id) == []
    end
  end

  describe "get_integration/2" do
    test "returns integration by org and provider", %{organization: org} do
      {:ok, created} = Integrations.create_integration(org.id, %{provider: "preseem"})
      assert {:ok, fetched} = Integrations.get_integration(org.id, "preseem")
      assert fetched.id == created.id
    end

    test "returns error when not found", %{organization: org} do
      assert {:error, :not_found} = Integrations.get_integration(org.id, "preseem")
    end
  end

  describe "get_integration!/2" do
    test "returns integration by org and provider", %{organization: org} do
      {:ok, created} = Integrations.create_integration(org.id, %{provider: "preseem"})
      fetched = Integrations.get_integration!(org.id, "preseem")
      assert fetched.id == created.id
    end

    test "raises when not found", %{organization: org} do
      assert_raise Ecto.NoResultsError, fn ->
        Integrations.get_integration!(org.id, "preseem")
      end
    end
  end

  describe "create_integration/2" do
    test "creates with valid attrs", %{organization: org} do
      attrs = %{provider: "preseem", credentials: %{"api_key" => "test-123"}, enabled: true}
      assert {:ok, %Integration{} = integration} = Integrations.create_integration(org.id, attrs)
      assert integration.provider == "preseem"
      assert integration.credentials == %{"api_key" => "test-123"}
      assert integration.enabled == true
      assert integration.organization_id == org.id
    end

    test "rejects duplicate provider per org", %{organization: org} do
      {:ok, _} = Integrations.create_integration(org.id, %{provider: "preseem"})
      assert {:error, changeset} = Integrations.create_integration(org.id, %{provider: "preseem"})
      assert "has already been taken" in errors_on(changeset).provider
    end
  end

  describe "update_integration/2" do
    test "updates credentials", %{organization: org} do
      {:ok, integration} =
        Integrations.create_integration(org.id, %{
          provider: "preseem",
          credentials: %{"api_key" => "old-key"}
        })

      assert {:ok, updated} =
               Integrations.update_integration(integration, %{credentials: %{"api_key" => "new-key"}})

      assert updated.credentials == %{"api_key" => "new-key"}
    end

    test "updates enabled flag", %{organization: org} do
      {:ok, integration} =
        Integrations.create_integration(org.id, %{provider: "preseem", enabled: false})

      assert {:ok, updated} = Integrations.update_integration(integration, %{enabled: true})
      assert updated.enabled == true
    end
  end

  describe "update_sync_status/2" do
    test "updates last_synced_at and last_sync_status", %{organization: org} do
      {:ok, integration} = Integrations.create_integration(org.id, %{provider: "preseem"})
      assert integration.last_sync_status == "never"
      assert integration.last_synced_at == nil

      assert {:ok, updated} = Integrations.update_sync_status(integration, "success")
      assert updated.last_sync_status == "success"
      assert updated.last_synced_at
    end
  end

  describe "delete_integration/1" do
    test "deletes the integration", %{organization: org} do
      {:ok, integration} = Integrations.create_integration(org.id, %{provider: "preseem"})
      assert {:ok, _} = Integrations.delete_integration(integration)
      assert {:error, :not_found} = Integrations.get_integration(org.id, "preseem")
    end
  end

  describe "change_integration/2" do
    test "returns a changeset", %{organization: org} do
      {:ok, integration} = Integrations.create_integration(org.id, %{provider: "preseem"})
      assert %Ecto.Changeset{} = Integrations.change_integration(integration)
    end
  end

  describe "list_enabled_integrations/1" do
    test "returns only enabled integrations for a provider", %{organization: org} do
      {:ok, _} = Integrations.create_integration(org.id, %{provider: "preseem", enabled: true})

      user2 = user_fixture()
      org2 = organization_fixture(user2.id)
      {:ok, _} = Integrations.create_integration(org2.id, %{provider: "preseem", enabled: false})

      enabled = Integrations.list_enabled_integrations("preseem")
      assert length(enabled) == 1
      assert hd(enabled).organization_id == org.id
    end
  end
end
