defmodule Towerops.Accounts.UserConsent do
  @moduledoc """
  User consent schema for tracking consent to privacy policy and terms of service.

  Stores consent records with versioning to comply with GDPR and privacy regulations.
  Allows users to withdraw consent at any time.
  """
  use Ecto.Schema

  import Ecto.Changeset

  alias Towerops.Accounts.User

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "user_consents" do
    belongs_to :user, User

    field :consent_type, :string
    field :version, :string
    field :granted_at, :utc_datetime
    field :revoked_at, :utc_datetime

    timestamps(type: :utc_datetime)
  end

  @consent_types ~w(privacy_policy terms_of_service)
  @current_privacy_policy_version "1.0"
  @current_terms_of_service_version "1.0"

  @doc """
  Returns the list of valid consent types.
  """
  def consent_types, do: @consent_types

  @doc """
  Returns the current version for a given consent type.
  """
  def current_version("privacy_policy"), do: @current_privacy_policy_version
  def current_version("terms_of_service"), do: @current_terms_of_service_version

  @doc """
  Changeset for granting consent.
  """
  def grant_changeset(consent \\ %__MODULE__{}, attrs) do
    consent
    |> cast(attrs, [:user_id, :consent_type, :version, :granted_at])
    |> validate_required([:user_id, :consent_type, :version, :granted_at])
    |> validate_inclusion(:consent_type, @consent_types)
    |> foreign_key_constraint(:user_id)
  end

  @doc """
  Changeset for revoking consent.
  """
  def revoke_changeset(consent, attrs \\ %{}) do
    consent
    |> cast(attrs, [:revoked_at])
    |> validate_required([:revoked_at])
    |> validate_not_already_revoked()
  end

  defp validate_not_already_revoked(changeset) do
    # Check the original struct's revoked_at, not the changeset's pending changes
    if changeset.data.revoked_at do
      add_error(changeset, :revoked_at, "consent already revoked")
    else
      changeset
    end
  end
end
