defmodule Towerops.OrganizationsTest do
  use Towerops.DataCase

  import Towerops.AccountsFixtures

  alias Towerops.Devices.Device
  alias Towerops.Organizations

  describe "organizations" do
    setup do
      user = user_fixture()
      %{user: user}
    end

    test "list_user_organizations/1 returns all organizations for a user", %{user: user} do
      {:ok, org1} = Organizations.create_organization(%{name: "Org 1"}, user.id)
      # Use bypass_limits to create second org for testing
      {:ok, org2} = Organizations.create_organization(%{name: "Org 2"}, user.id, bypass_limits: true)

      orgs = Organizations.list_user_organizations(user.id)
      assert length(orgs) == 2
      org_ids = Enum.map(orgs, & &1.id)
      assert org1.id in org_ids
      assert org2.id in org_ids
    end

    test "list_user_organizations/1 returns empty list for user with no orgs" do
      user = user_fixture()
      assert Organizations.list_user_organizations(user.id) == []
    end

    test "get_organization!/1 returns the organization with given id", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      assert Organizations.get_organization!(organization.id).id == organization.id
    end

    test "get_organization_by_slug!/1 returns the organization with given slug", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      assert Organizations.get_organization_by_slug!(organization.slug).id == organization.id
    end

    test "create_organization/2 with valid data creates organization", %{user: user} do
      valid_attrs = %{name: "New Organization"}

      assert {:ok, organization} = Organizations.create_organization(valid_attrs, user.id)
      assert organization.name == "New Organization"
      assert organization.slug
    end

    test "create_organization/2 creates owner membership", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      membership = Organizations.get_membership(organization.id, user.id)
      assert membership.role == :owner
    end

    test "create_organization/2 with invalid data returns error changeset" do
      user = user_fixture()
      assert {:error, changeset} = Organizations.create_organization(%{name: nil}, user.id)
      assert "can't be blank" in errors_on(changeset).name
    end

    test "update_organization/2 with valid data updates the organization", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      update_attrs = %{name: "Updated Org"}
      assert {:ok, updated} = Organizations.update_organization(organization, update_attrs)
      assert updated.name == "Updated Org"
    end

    test "update_organization/2 with invalid data returns error changeset", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      assert {:error, changeset} = Organizations.update_organization(organization, %{name: nil})
      assert "can't be blank" in errors_on(changeset).name
    end

    test "delete_organization/1 deletes the organization", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      assert {:ok, _} = Organizations.delete_organization(organization)
      assert_raise Ecto.NoResultsError, fn -> Organizations.get_organization!(organization.id) end
    end

    test "change_organization/1 returns an organization changeset", %{user: user} do
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      assert %Ecto.Changeset{} = Organizations.change_organization(organization)
    end
  end

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

    test "get_membership/2 returns the membership", %{user: user, organization: organization} do
      membership = Organizations.get_membership(organization.id, user.id)
      assert membership.user_id == user.id
      assert membership.organization_id == organization.id
    end

    test "get_membership/2 returns nil when membership doesn't exist", %{organization: organization} do
      other_user = user_fixture()
      assert Organizations.get_membership(organization.id, other_user.id) == nil
    end

    test "get_membership!/2 returns the membership", %{user: user, organization: organization} do
      membership = Organizations.get_membership!(organization.id, user.id)
      assert membership.user_id == user.id
    end

    test "get_membership!/2 raises when membership doesn't exist", %{organization: organization} do
      other_user = user_fixture()

      assert_raise Ecto.NoResultsError, fn ->
        Organizations.get_membership!(organization.id, other_user.id)
      end
    end

    test "list_organization_memberships/1 returns all memberships", %{
      user: user,
      organization: organization
    } do
      # Add another member
      other_user = user_fixture()

      {:ok, _membership} =
        Organizations.create_membership(%{
          organization_id: organization.id,
          user_id: other_user.id,
          role: :member
        })

      memberships = Organizations.list_organization_memberships(organization.id)
      assert length(memberships) == 2
      user_ids = Enum.map(memberships, & &1.user_id)
      assert user.id in user_ids
      assert other_user.id in user_ids
    end

    test "list_organization_notification_recipients/1 returns owners and admins", %{
      organization: organization
    } do
      admin = user_fixture()
      member = user_fixture()

      {:ok, _admin_membership} =
        Organizations.create_membership(%{
          organization_id: organization.id,
          user_id: admin.id,
          role: :admin
        })

      {:ok, _member_membership} =
        Organizations.create_membership(%{
          organization_id: organization.id,
          user_id: member.id,
          role: :member
        })

      recipients = Organizations.list_organization_notification_recipients(organization.id)
      recipient_ids = Enum.map(recipients, & &1.id)

      # Owner and admin should be in recipients
      assert admin.id in recipient_ids
      # Member should NOT be in recipients
      refute member.id in recipient_ids
    end

    test "create_membership/1 with valid data creates membership", %{organization: organization} do
      new_user = user_fixture()

      valid_attrs = %{
        organization_id: organization.id,
        user_id: new_user.id,
        role: :member
      }

      assert {:ok, membership} = Organizations.create_membership(valid_attrs)
      assert membership.role == :member
      assert membership.user_id == new_user.id
    end

    test "create_membership/1 with invalid data returns error changeset" do
      assert {:error, changeset} = Organizations.create_membership(%{})
      assert "can't be blank" in errors_on(changeset).organization_id
    end

    test "update_membership/2 changes user role", %{user: user, organization: organization} do
      membership = Organizations.get_membership!(organization.id, user.id)

      assert {:ok, updated} = Organizations.update_membership(membership, %{role: :admin})
      assert updated.role == :admin
    end

    test "delete_membership/1 deletes the membership", %{organization: organization} do
      new_user = user_fixture()

      {:ok, membership} =
        Organizations.create_membership(%{
          organization_id: organization.id,
          user_id: new_user.id,
          role: :member
        })

      assert {:ok, _} = Organizations.delete_membership(membership)
      assert Organizations.get_membership(organization.id, new_user.id) == nil
    end
  end

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

    test "list_pending_invitations/1 returns pending invitations", %{
      owner: owner,
      organization: organization
    } do
      {:ok, invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "invited@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: "test-token-#{System.unique_integer()}",
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second)
        })

      invitations = Organizations.list_pending_invitations(organization.id)
      assert length(invitations) == 1
      assert hd(invitations).id == invitation.id
    end

    test "list_pending_invitations/1 excludes accepted invitations", %{
      owner: owner,
      organization: organization
    } do
      {:ok, invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "invited@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: "test-token-#{System.unique_integer()}",
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second),
          accepted_at: DateTime.truncate(DateTime.utc_now(), :second)
        })

      invitations = Organizations.list_pending_invitations(organization.id)
      refute Enum.any?(invitations, &(&1.id == invitation.id))
    end

    test "list_pending_invitations/1 excludes expired invitations", %{
      owner: owner,
      organization: organization
    } do
      {:ok, invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "invited@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: "test-token-#{System.unique_integer()}",
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), -1, :day), :second)
        })

      invitations = Organizations.list_pending_invitations(organization.id)
      refute Enum.any?(invitations, &(&1.id == invitation.id))
    end

    test "create_invitation/1 with valid data creates invitation", %{
      owner: owner,
      organization: organization
    } do
      valid_attrs = %{
        organization_id: organization.id,
        email: "test@example.com",
        role: :member,
        invited_by_id: owner.id,
        token: "unique-token-#{System.unique_integer()}",
        expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second)
      }

      assert {:ok, invitation} = Organizations.create_invitation(valid_attrs)
      assert invitation.email == "test@example.com"
      assert invitation.role == :member
    end

    test "get_invitation_by_token/1 returns invitation", %{
      owner: owner,
      organization: organization
    } do
      token = "test-token-#{System.unique_integer()}"

      {:ok, _invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "test@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: token,
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second)
        })

      invitation = Organizations.get_invitation_by_token(token)
      assert invitation.token == token
    end

    test "get_invitation_by_token/1 returns nil for accepted invitation", %{
      owner: owner,
      organization: organization
    } do
      token = "test-token-#{System.unique_integer()}"

      {:ok, _invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "test@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: token,
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second),
          accepted_at: DateTime.truncate(DateTime.utc_now(), :second)
        })

      assert Organizations.get_invitation_by_token(token) == nil
    end

    test "accept_invitation/2 creates membership and marks invitation accepted", %{
      owner: owner,
      organization: organization
    } do
      token = "test-token-#{System.unique_integer()}"

      {:ok, invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "test@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: token,
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second)
        })

      new_user = user_fixture()
      assert {:ok, membership} = Organizations.accept_invitation(invitation, new_user.id)
      assert membership.user_id == new_user.id
      assert membership.role == :member

      # Invitation should no longer be retrievable
      assert Organizations.get_invitation_by_token(token) == nil
    end

    test "delete_invitation/1 deletes the invitation", %{
      owner: owner,
      organization: organization
    } do
      {:ok, invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "test@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: "test-token-#{System.unique_integer()}",
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second)
        })

      assert {:ok, _} = Organizations.delete_invitation(invitation)
      assert Organizations.list_pending_invitations(organization.id) == []
    end
  end

  describe "user_has_access?/2" do
    test "returns true when user is member of organization" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      assert Organizations.user_has_access?(user.id, organization.id)
    end

    test "returns false when user is not member of organization" do
      user1 = user_fixture()
      user2 = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user1.id)

      refute Organizations.user_has_access?(user2.id, organization.id)
    end
  end

  describe "authorization" do
    setup do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      membership = Organizations.get_membership!(organization.id, user.id)
      %{membership: membership}
    end

    test "can?/3 delegates to Policy module", %{membership: membership} do
      # Owner can delete organization
      assert Organizations.can?(membership, :delete, :organization)

      # Change to member role
      {:ok, member_membership} = Organizations.update_membership(membership, %{role: :member})

      # Member cannot delete organization
      refute Organizations.can?(member_membership, :delete, :organization)
    end
  end

  describe "apply_snmp_config_to_all_equipment/1" do
    test "updates SNMP config for all devices in organization" do
      user = user_fixture()

      {:ok, organization} =
        Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, organization} =
        Organizations.update_organization(organization, %{
          snmp_version: "2c",
          snmp_community: "new-community"
        })

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, device1} =
        Towerops.Devices.create_device(%{
          name: "Device 1",
          ip_address: "192.168.1.1",
          snmp_enabled: true,
          snmp_version: "2c",
          snmp_community: "public",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, device2} =
        Towerops.Devices.create_device(%{
          name: "Device 2",
          ip_address: "192.168.1.2",
          snmp_enabled: true,
          snmp_version: "2c",
          snmp_community: "public",
          site_id: site.id,
          organization_id: organization.id
        })

      {count, _} = Organizations.apply_snmp_config_to_all_equipment(organization.id)
      assert count == 2

      updated_device1 = Repo.get!(Device, device1.id)
      assert updated_device1.snmp_version == "2c"
      assert updated_device1.snmp_community == "new-community"

      updated_device2 = Repo.get!(Device, device2.id)
      assert updated_device2.snmp_version == "2c"
      assert updated_device2.snmp_community == "new-community"
    end

    test "returns 0 when organization has no devices" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      {count, _} = Organizations.apply_snmp_config_to_all_equipment(organization.id)
      assert count == 0
    end
  end

  describe "apply_agent_to_all_equipment/1" do
    test "creates agent assignments for all devices when default agent is set" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, agent_token, _token} =
        Towerops.Agents.create_agent_token(organization.id, "Test Agent")

      {:ok, organization} =
        Organizations.update_organization(organization, %{
          default_agent_token_id: agent_token.id
        })

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, device1} =
        Towerops.Devices.create_device(%{
          name: "Device 1",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, device2} =
        Towerops.Devices.create_device(%{
          name: "Device 2",
          ip_address: "192.168.1.2",
          site_id: site.id,
          organization_id: organization.id
        })

      {count, _} = Organizations.apply_agent_to_all_equipment(organization.id)
      assert count == 2

      assignment1 = Towerops.Agents.get_device_assignment(device1.id)
      assert assignment1.agent_token_id == agent_token.id

      assignment2 = Towerops.Agents.get_device_assignment(device2.id)
      assert assignment2.agent_token_id == agent_token.id
    end

    test "deletes agent assignments when default agent is nil" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, device} =
        Towerops.Devices.create_device(%{
          name: "Test Device",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, agent_token, _token} =
        Towerops.Agents.create_agent_token(organization.id, "Test Agent")

      Towerops.Agents.assign_device_to_agent(agent_token.id, device.id)

      # Organization has no default agent set (nil)
      Organizations.apply_agent_to_all_equipment(organization.id)

      assert Towerops.Agents.get_device_assignment(device.id) == nil
    end

    test "replaces existing agent assignments" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, old_agent, _token1} =
        Towerops.Agents.create_agent_token(organization.id, "Old Agent")

      {:ok, new_agent, _token2} =
        Towerops.Agents.create_agent_token(organization.id, "New Agent")

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, device} =
        Towerops.Devices.create_device(%{
          name: "Test Device",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      Towerops.Agents.assign_device_to_agent(old_agent.id, device.id)

      {:ok, organization} =
        Organizations.update_organization(organization, %{
          default_agent_token_id: new_agent.id
        })

      Organizations.apply_agent_to_all_equipment(organization.id)

      assignment = Towerops.Agents.get_device_assignment(device.id)
      assert assignment.agent_token_id == new_agent.id
    end

    test "returns 0 when organization has no devices" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, agent_token, _token} =
        Towerops.Agents.create_agent_token(organization.id, "Test Agent")

      {:ok, organization} =
        Organizations.update_organization(organization, %{
          default_agent_token_id: agent_token.id
        })

      {count, _} = Organizations.apply_agent_to_all_equipment(organization.id)
      assert count == 0
    end
  end

  describe "organization creation with subscription limits" do
    test "blocks creating second free organization" do
      user = user_fixture()
      {:ok, _org1} = Organizations.create_organization(%{name: "Free Org 1"}, user.id)

      assert {:error, changeset} = Organizations.create_organization(%{name: "Free Org 2"}, user.id)

      assert %{
               base: [
                 "You already have a free organization. Upgrade your existing organization to create additional ones."
               ]
             } =
               errors_on(changeset)
    end

    test "allows creating first free organization" do
      user = user_fixture()

      assert {:ok, org} = Organizations.create_organization(%{name: "Free Org"}, user.id)
      assert org.subscription_plan == "free"
    end

    test "bypasses limit with bypass_limits option" do
      user = user_fixture()
      {:ok, _org1} = Organizations.create_organization(%{name: "Free Org 1"}, user.id)

      # Second free org succeeds with bypass
      assert {:ok, _org2} =
               Organizations.create_organization(
                 %{name: "Free Org 2"},
                 user.id,
                 bypass_limits: true
               )
    end

    test "invited members can create their own free organization" do
      owner = user_fixture()
      member = user_fixture()

      {:ok, organization} = Organizations.create_organization(%{name: "Owner's Org"}, owner.id)

      # Add member to organization
      {:ok, _membership} =
        Organizations.create_membership(%{
          user_id: member.id,
          organization_id: organization.id,
          role: :member
        })

      # Member can still create their own free org
      assert {:ok, _org} = Organizations.create_organization(%{name: "Member's Org"}, member.id)
    end

    test "create_organization/3 with explicit free subscription plan" do
      user = user_fixture()

      # Explicitly specify "free" subscription plan
      assert {:ok, org} =
               Organizations.create_organization(
                 %{name: "Free Org", subscription_plan: "free"},
                 user.id
               )

      assert org.subscription_plan == "free"
    end
  end

  describe "update_organization/2 MikroTik propagation" do
    test "propagates MikroTik settings when changed" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, device} =
        Towerops.Devices.create_device(%{
          name: "MikroTik Device",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id,
          manufacturer: "MikroTik"
        })

      # Update organization MikroTik settings
      {:ok, updated_org} =
        Organizations.update_organization(organization, %{
          mikrotik_username: "admin",
          mikrotik_password: "password123",
          mikrotik_port: 8729,
          mikrotik_use_ssl: true,
          mikrotik_enabled: true
        })

      assert updated_org.mikrotik_username == "admin"
      assert updated_org.mikrotik_port == 8729
      assert updated_org.mikrotik_use_ssl == true
      assert updated_org.mikrotik_enabled == true

      # Verify device credential source is "organization" (inherits directly from org)
      updated_device = Repo.get!(Device, device.id)
      assert updated_device.mikrotik_credential_source == "organization"

      # Verify the device received the organization's MikroTik settings through propagation
      assert updated_device.mikrotik_username == "admin"
      assert updated_device.mikrotik_port == 8729
      assert updated_device.mikrotik_use_ssl == true
      assert updated_device.mikrotik_enabled == true
    end

    test "propagates when individual MikroTik fields change" do
      user = user_fixture()

      {:ok, organization} =
        Organizations.create_organization(
          %{
            name: "Test Org",
            mikrotik_username: "original",
            mikrotik_password: "oldpass"
          },
          user.id
        )

      {:ok, site} =
        Towerops.Sites.create_site(%{
          name: "Test Site",
          organization_id: organization.id
        })

      {:ok, _device} =
        Towerops.Devices.create_device(%{
          name: "MikroTik Device",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id,
          manufacturer: "MikroTik"
        })

      # Change only username - should still propagate
      {:ok, _updated} =
        Organizations.update_organization(organization, %{
          mikrotik_username: "newuser"
        })

      # Change only password - should propagate
      organization = Organizations.get_organization!(organization.id)

      {:ok, _updated} =
        Organizations.update_organization(organization, %{
          mikrotik_password: "newpass"
        })

      # Change only port - should propagate
      organization = Organizations.get_organization!(organization.id)

      {:ok, _updated} =
        Organizations.update_organization(organization, %{
          mikrotik_port: 8728
        })

      # Change only use_ssl - should propagate
      organization = Organizations.get_organization!(organization.id)

      {:ok, _updated} =
        Organizations.update_organization(organization, %{
          mikrotik_use_ssl: false
        })

      # Change only enabled - should propagate
      organization = Organizations.get_organization!(organization.id)

      {:ok, _updated} =
        Organizations.update_organization(organization, %{
          mikrotik_enabled: false
        })
    end
  end

  describe "get_default_membership/1" do
    test "returns the default membership for a user" do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Default Org"}, user.id)

      membership = Organizations.get_default_membership(user.id)
      assert membership.organization_id == organization.id
      assert membership.is_default == true
      assert membership.organization.id == organization.id
    end

    test "returns nil when user has no default membership" do
      user = user_fixture()
      assert Organizations.get_default_membership(user.id) == nil
    end
  end

  describe "set_default_organization/2" do
    test "sets an organization as the user's default" do
      user = user_fixture()
      {:ok, _org1} = Organizations.create_organization(%{name: "Org 1"}, user.id)
      {:ok, org2} = Organizations.create_organization(%{name: "Org 2"}, user.id, bypass_limits: true)

      assert {:ok, returned_org} = Organizations.set_default_organization(user.id, org2.id)
      assert returned_org.id == org2.id

      # Verify org2 is now default
      membership = Organizations.get_default_membership(user.id)
      assert membership.organization_id == org2.id
    end

    test "returns error when user has no access to organization" do
      user1 = user_fixture()
      user2 = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user1.id)

      assert {:error, :not_found} = Organizations.set_default_organization(user2.id, organization.id)
    end
  end

  describe "accept_invitation/2 error handling" do
    test "returns error when membership creation fails" do
      owner = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, owner.id)

      token = "test-token-#{System.unique_integer()}"

      {:ok, invitation} =
        Organizations.create_invitation(%{
          organization_id: organization.id,
          email: "test@example.com",
          role: :member,
          invited_by_id: owner.id,
          token: token,
          expires_at: DateTime.truncate(DateTime.add(DateTime.utc_now(), 7, :day), :second)
        })

      # Create a membership first so the accept will fail with unique constraint
      new_user = user_fixture()

      {:ok, _existing_membership} =
        Organizations.create_membership(%{
          organization_id: organization.id,
          user_id: new_user.id,
          role: :admin
        })

      # Accepting invitation should fail because membership already exists
      assert {:error, _changeset} = Organizations.accept_invitation(invitation, new_user.id)
    end
  end
end
