# == Schema Information
#
# Table name: organizations
#
#  id                     :uuid             not null, primary key
#  api_key                :string
#  created_by             :string           not null
#  name                   :string           not null
#  slug                   :string           indexed
#  sso                    :boolean          default(FALSE)
#  sso_configuration_link :string
#  sso_domains            :string           default([]), is an Array
#  sso_protocol           :string
#  sso_tenant_name        :string
#  status                 :string           not null, indexed
#  subscribed             :boolean          default(FALSE)
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#  sso_tenant_id          :string
#
class Accounts::Organization < ApplicationRecord
  extend FriendlyId
  has_paper_trail

  has_many :memberships, -> { kept }, dependent: :delete_all, inverse_of: :organization
  has_many :teams, -> { sequential }, dependent: :delete_all, inverse_of: :organization
  has_many :users, through: :memberships, dependent: :delete_all
  has_many :apps, -> { sequential }, dependent: :destroy, inverse_of: :organization
  has_many :releases, through: :apps
  has_many :invites, dependent: :destroy
  has_one :custom_storage, class_name: "Accounts::CustomStorage", dependent: :destroy, inverse_of: :organization

  enum :status, {active: "active", dormant: "dormant", guest: "guest"}

  encrypts :api_key, deterministic: true

  after_create :rotate_api_key

  validates :name, presence: true

  friendly_id :name, use: :slugged

  normalizes :name, with: ->(name) { name.squish }

  scope :sequential, -> { reorder("organizations.created_at ASC") }

  def self.find_sso_org_by_domain(domain)
    where(sso: true).where(":domain = ANY (sso_domains)", domain:).first
  end

  def valid_sso_domain?(email)
    sso_domains.include?(Mail::Address.new(email).domain)
  end

  def allow_email_auth_for_sso?
    Flipper.enabled?(:allow_email_auth_for_sso, self)
  end

  def demo?
    Flipper.enabled?(:demo_mode, self)
  end

  def build_notes_in_workflow?
    Flipper.enabled?(:build_notes_in_workflow, self)
  end

  def merge_only_build_notes?
    Flipper.enabled?(:merge_only_build_notes, self)
  end

  def tester_notes_in_beta_releases?
    Flipper.enabled?(:tester_notes_in_beta_releases, self)
  end

  # TODO: This should eventually become a config, but right now this is only implemented for the Bitbucket integration
  # So we currently do this as a feature flag for specific orgs
  def single_pr_backmerge_for_multi_commit_push?
    Flipper.enabled?(:single_pr_backmerge_for_multi_commit_push, self)
  end

  def owner
    users.includes(:memberships).where(memberships: {role: "owner"}).sole
  end

  def rotate_api_key
    update(api_key: SecureRandom.hex)
  end

  def default_app
    apps.first
  end

  def members
    users.includes(memberships: :organization, invitations: :organization)
  end

  def pending_invites
    invites.includes(:sender).not_accepted
  end

  def team_colors
    colors = teams.pluck(:name, :color).to_h || {}
    colors[Accounts::Team::UNKNOWN_TEAM_NAME] = Accounts::Team::UNKNOWN_TEAM_COLOR
    colors[Accounts::Team::TRAMLINE_TEAM_NAME] = Accounts::Team::TRAMLINE_TEAM_COLOR
    colors
  end

  def team_names
    return unless teams.exists?
    teams.pluck(:name) << Accounts::Team::UNKNOWN_TEAM_NAME
  end

  def teams_supported?
    teams.exists?
  end

  def team_options
    teams.pluck(:name, :id).push([Accounts::Team::UNKNOWN_TEAM_NAME, nil])
  end
end
