defmodule Towerops.Organizations.SubscriptionLimitsTest do
  use Towerops.DataCase

  import Towerops.AccountsFixtures

  alias Towerops.Devices
  alias Towerops.Organizations
  alias Towerops.Organizations.SubscriptionLimits
  alias Towerops.Sites

  describe "device_limit/1" do
    test "returns 10 for free plan" do
      assert SubscriptionLimits.device_limit("free") == 10
    end

    test "returns unlimited for any non-free plan" do
      # Future: when other plans are added, they will return :unlimited
      assert SubscriptionLimits.device_limit("paid") == :unlimited
      assert SubscriptionLimits.device_limit("premium") == :unlimited
      assert SubscriptionLimits.device_limit("enterprise") == :unlimited
    end
  end

  describe "check_device_limit/1" do
    setup do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      {:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id})
      %{organization: organization, site: site}
    end

    test "returns ok when organization has no devices", %{organization: organization} do
      assert {:ok, :within_limit} = SubscriptionLimits.check_device_limit(organization)
    end

    test "returns ok when organization has devices under limit", %{
      organization: organization,
      site: site
    } do
      # Create 5 devices
      for i <- 1..5 do
        create_device(site.id, "Device #{i}", "192.168.1.#{i}")
      end

      organization = Repo.reload!(organization)
      assert {:ok, :within_limit} = SubscriptionLimits.check_device_limit(organization)
    end

    test "returns error when organization is at device limit", %{
      organization: organization,
      site: site
    } do
      # Create 10 devices (the limit)
      for i <- 1..10 do
        create_device(site.id, "Device #{i}", "192.168.1.#{i}")
      end

      organization = Repo.reload!(organization)
      assert {:error, :at_limit, 10, 10} = SubscriptionLimits.check_device_limit(organization)
    end

    test "returns error when organization is over device limit", %{
      organization: organization,
      site: site
    } do
      # Create 12 devices (over the limit)
      for i <- 1..12 do
        create_device(site.id, "Device #{i}", "192.168.1.#{i}")
      end

      organization = Repo.reload!(organization)
      assert {:error, :at_limit, 12, 10} = SubscriptionLimits.check_device_limit(organization)
    end
  end

  describe "device_quota/1" do
    setup do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      {:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id})
      %{organization: organization, site: site}
    end

    test "returns {0, 10} for free org with no devices", %{organization: organization} do
      assert {0, 10} = SubscriptionLimits.device_quota(organization)
    end

    test "returns {5, 10} for free org with 5 devices", %{organization: organization, site: site} do
      for i <- 1..5 do
        create_device(site.id, "Device #{i}", "192.168.1.#{i}")
      end

      organization = Repo.reload!(organization)
      assert {5, 10} = SubscriptionLimits.device_quota(organization)
    end
  end

  describe "can_create_free_organization?/1" do
    test "returns true when user has no free organizations" do
      user = user_fixture()
      assert SubscriptionLimits.can_create_free_organization?(user.id) == true
    end

    test "returns false when user owns one free organization" do
      user = user_fixture()
      {:ok, _org} = Organizations.create_organization(%{name: "Free Org"}, user.id)

      assert SubscriptionLimits.can_create_free_organization?(user.id) == false
    end

    test "returns true when user is member but not owner of free organization" do
      owner = user_fixture()
      member = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Free 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 SubscriptionLimits.can_create_free_organization?(member.id) == true
    end
  end

  describe "count_user_owned_free_organizations/1" do
    test "returns 0 when user has no organizations" do
      user = user_fixture()
      assert SubscriptionLimits.count_user_owned_free_organizations(user.id) == 0
    end

    test "returns 1 when user owns one free organization" do
      user = user_fixture()
      {:ok, _org} = Organizations.create_organization(%{name: "Free Org"}, user.id)

      assert SubscriptionLimits.count_user_owned_free_organizations(user.id) == 1
    end

    test "returns 0 when user is member but not owner" do
      owner = user_fixture()
      member = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Free Org"}, owner.id)

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

      assert SubscriptionLimits.count_user_owned_free_organizations(member.id) == 0
    end
  end

  describe "count_organization_devices/1" do
    setup do
      user = user_fixture()
      {:ok, organization} = Organizations.create_organization(%{name: "Test Org"}, user.id)
      {:ok, site} = Sites.create_site(%{name: "Test Site", organization_id: organization.id})
      %{organization: organization, site: site}
    end

    test "returns 0 for organization with no devices", %{organization: organization} do
      assert SubscriptionLimits.count_organization_devices(organization.id) == 0
    end

    test "returns correct count for organization with devices", %{
      organization: organization,
      site: site
    } do
      for i <- 1..7 do
        create_device(site.id, "Device #{i}", "192.168.1.#{i}")
      end

      assert SubscriptionLimits.count_organization_devices(organization.id) == 7
    end

    test "counts devices across multiple sites", %{organization: organization, site: site1} do
      {:ok, site2} = Sites.create_site(%{name: "Site 2", organization_id: organization.id})

      for i <- 1..3 do
        create_device(site1.id, "Site1 Device #{i}", "192.168.1.#{i}")
      end

      for i <- 4..8 do
        create_device(site2.id, "Site2 Device #{i}", "192.168.2.#{i}")
      end

      assert SubscriptionLimits.count_organization_devices(organization.id) == 8
    end

    test "counts devices without site assignment when sites are disabled", %{
      organization: organization
    } do
      # Create devices directly assigned to organization (no site)
      for i <- 1..5 do
        create_device_without_site(organization.id, "Device #{i}", "192.168.1.#{i}")
      end

      assert SubscriptionLimits.count_organization_devices(organization.id) == 5
    end

    test "counts both site-assigned and unassigned devices", %{
      organization: organization,
      site: site
    } do
      # Create 3 devices assigned to site
      for i <- 1..3 do
        create_device(site.id, "Site Device #{i}", "192.168.1.#{i}")
      end

      # Create 2 devices without site assignment
      for i <- 4..5 do
        create_device_without_site(organization.id, "Org Device #{i}", "192.168.1.#{i}")
      end

      assert SubscriptionLimits.count_organization_devices(organization.id) == 5
    end
  end

  # Helper functions

  defp create_device(site_id, name, ip_address) do
    site = Sites.get_site!(site_id)

    {:ok, device} =
      Devices.create_device(
        %{
          name: name,
          ip_address: ip_address,
          site_id: site_id,
          organization_id: site.organization_id,
          monitoring_enabled: false,
          snmp_enabled: false
        },
        bypass_limits: true
      )

    device
  end

  defp create_device_without_site(organization_id, name, ip_address) do
    {:ok, device} =
      Devices.create_device(
        %{
          name: name,
          ip_address: ip_address,
          organization_id: organization_id,
          monitoring_enabled: false,
          snmp_enabled: false
        },
        bypass_limits: true
      )

    device
  end
end
