defmodule Towerops.Integrations.IntegrationTest do
  use Towerops.DataCase, async: true

  import Towerops.AccountsFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Integrations.Integration

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

  describe "changeset/2" do
    test "valid changeset with required fields", %{organization: org} do
      attrs = %{
        organization_id: org.id,
        provider: "preseem",
        enabled: true,
        credentials: %{"api_key" => "test-key-123"}
      }

      changeset = Integration.changeset(%Integration{}, attrs)
      assert changeset.valid?
    end

    test "requires organization_id" do
      attrs = %{provider: "preseem"}
      changeset = Integration.changeset(%Integration{}, attrs)
      refute changeset.valid?
      assert "can't be blank" in errors_on(changeset).organization_id
    end

    test "requires provider" do
      attrs = %{organization_id: Ecto.UUID.generate()}
      changeset = Integration.changeset(%Integration{}, attrs)
      refute changeset.valid?
      assert "can't be blank" in errors_on(changeset).provider
    end

    test "validates provider is a known value" do
      attrs = %{organization_id: Ecto.UUID.generate(), provider: "unknown_provider"}
      changeset = Integration.changeset(%Integration{}, attrs)
      refute changeset.valid?
      assert "is invalid" in errors_on(changeset).provider
    end

    test "validates sync_interval_minutes is positive" do
      attrs = %{
        organization_id: Ecto.UUID.generate(),
        provider: "preseem",
        sync_interval_minutes: 0
      }

      changeset = Integration.changeset(%Integration{}, attrs)
      refute changeset.valid?
      assert "must be greater than 0" in errors_on(changeset).sync_interval_minutes
    end

    test "validates last_sync_status is a known value" do
      attrs = %{
        organization_id: Ecto.UUID.generate(),
        provider: "preseem",
        last_sync_status: "bogus"
      }

      changeset = Integration.changeset(%Integration{}, attrs)
      refute changeset.valid?
      assert "is invalid" in errors_on(changeset).last_sync_status
    end

    test "enforces unique constraint on org + provider", %{organization: org} do
      attrs = %{organization_id: org.id, provider: "preseem"}
      {:ok, _} = %Integration{} |> Integration.changeset(attrs) |> Repo.insert()
      assert {:error, changeset} = %Integration{} |> Integration.changeset(attrs) |> Repo.insert()
      assert "has already been taken" in errors_on(changeset).provider
    end
  end

  describe "credentials encryption" do
    test "credentials are encrypted at rest", %{organization: org} do
      attrs = %{
        organization_id: org.id,
        provider: "preseem",
        credentials: %{"api_key" => "super-secret-key"}
      }

      {:ok, integration} = %Integration{} |> Integration.changeset(attrs) |> Repo.insert()
      reloaded = Repo.get!(Integration, integration.id)
      assert reloaded.credentials == %{"api_key" => "super-secret-key"}

      raw =
        Repo.one(
          from i in "integrations",
            where: i.id == type(^integration.id, :binary_id),
            select: i.credentials
        )

      refute raw == Jason.encode!(attrs.credentials)
    end
  end
end
