defmodule Towerops.Organizations.SubscriptionLimits do
  @moduledoc """
  Subscription plan limits and quota enforcement.

  Currently supports:
  - Free plan: 10 devices max, 1 owned organization per user
  - Future plans can be added here (per-device pricing, etc.)
  """

  import Ecto.Query

  alias Towerops.Devices.Device
  alias Towerops.Organizations.Membership
  alias Towerops.Organizations.Organization
  alias Towerops.Repo

  @free_device_limit 10

  @doc """
  Returns the device limit for a given subscription plan.

  ## Examples

      iex> device_limit("free")
      10

      iex> device_limit("paid")
      :unlimited
  """
  def device_limit("free"), do: @free_device_limit
  def device_limit(_other), do: :unlimited

  @doc """
  Checks if an organization is within its device quota.

  Returns `{:ok, :within_limit}` if the organization can add more devices.
  Returns `{:error, :at_limit, current, max}` if at or over the limit.

  ## Examples

      iex> check_device_limit(%Organization{subscription_plan: "free"})
      {:ok, :within_limit}

      iex> check_device_limit(%Organization{subscription_plan: "free"})
      {:error, :at_limit, 10, 10}
  """
  def check_device_limit(%Organization{} = organization) do
    case device_limit(organization.subscription_plan) do
      :unlimited ->
        {:ok, :within_limit}

      max_devices ->
        current = count_organization_devices(organization.id)

        if current >= max_devices do
          {:error, :at_limit, current, max_devices}
        else
          {:ok, :within_limit}
        end
    end
  end

  @doc """
  Returns the current device count and limit for an organization.

  Returns `{current_count, limit}` where limit is either an integer or `:unlimited`.

  ## Examples

      iex> device_quota(%Organization{id: "...", subscription_plan: "free"})
      {5, 10}

      iex> device_quota(%Organization{id: "...", subscription_plan: "paid"})
      {45, :unlimited}
  """
  def device_quota(%Organization{} = organization) do
    current = count_organization_devices(organization.id)
    limit = device_limit(organization.subscription_plan)
    {current, limit}
  end

  @doc """
  Checks if a user can create a free organization.

  Users are limited to owning 1 free organization. They can create unlimited
  paid organizations or be invited as members to unlimited organizations.

  Returns `true` if the user can create another free organization, `false` otherwise.

  ## Examples

      iex> can_create_free_organization?(user_id)
      true

      iex> can_create_free_organization?(user_id)
      false
  """
  def can_create_free_organization?(user_id) do
    count_user_owned_free_organizations(user_id) < 1
  end

  @doc """
  Counts how many free organizations a user owns.

  Only counts organizations where the user has the `:owner` role.
  Memberships as admin/member/viewer do not count.

  ## Examples

      iex> count_user_owned_free_organizations(user_id)
      1

      iex> count_user_owned_free_organizations(user_id)
      0
  """
  def count_user_owned_free_organizations(user_id) do
    Repo.aggregate(
      from(o in Organization,
        join: m in Membership,
        on: m.organization_id == o.id,
        where: m.user_id == ^user_id,
        where: m.role == :owner,
        where: o.subscription_plan == "free"
      ),
      :count
    )
  end

  @doc """
  Counts total devices for an organization.

  Counts all devices belonging to the organization, whether assigned to a site or not.
  """
  def count_organization_devices(organization_id) do
    Repo.aggregate(
      from(d in Device,
        where: d.organization_id == ^organization_id
      ),
      :count
    )
  end
end
