# frozen_string_literal: false

# @!parse
#   class ActiveRecord::Migration
#     # Rename a foreign key
#     #
#     # @param [#to_s] table (nil) The qualified name of the table
#     # @param [#to_s] reference (nil) The qualified name of the reference table
#     # @option options [#to_s] :name (nil) The current name of the foreign key
#     # @option options [#to_s] :to (nil) The new name for the foreign key
#     # @option options [Array<#to_s>] :columns ([]) The list of columns of the table
#     # @option options [#to_s] :column (nil) An alias for :columns for the case of single-column keys
#     # @option options [Array<#to_s>] :primary_key ([]) The list of columns of the reference table
#     # @yield [k] the block with the key's definition
#     # @yieldparam Object receiver of methods specifying the foreign key
#     # @return [void]
#     #
#     # You can rename the foreign key constraint identified by its explicit name:
#     #
#     # ```ruby
#     # rename_foreign_key :users,
#     #                    name: "user_roles_fk",
#     #                    to: "constraints.users_by_roles_fk"
#     # ```
#     #
#     # The key can also be found in the database by table/reference/columns/pk
#     #
#     # ```ruby
#     # rename_foreign_key :users, :roles, primary_key: "name", to: "user_roles"
#     # ```
#     #
#     # If a new name is missed, then the name will be reset to the auto-generated one:
#     #
#     # ```ruby
#     # rename_foreign_key :users, "user_roles_fk"
#     # ```
#     #
#     # The operation is always reversible.
#     def rename_foreign_key(table, reference, **options, &block); end
#   end
module PGTrunk::Operations::ForeignKeys
  #
  # Definition for the `rename_foreign_key` operation
  #
  class RenameForeignKey < Base
    # The name can be looked for in the database.
    # This is necessary because the name generated by `rails` inside the table
    # is different from the name generated by the `add_foreign_key`.
    after_initialize { self.name = current_name if name.blank? }
    # Reset the name to default when `to:` option is missed or set to `nil`
    after_initialize { self.new_name = generated_name if new_name.blank? }

    validates :new_name, presence: true
    validates :if_exists, :if_not_exists, :match, absence: true

    def to_sql(_version)
      <<~SQL.squish
        ALTER TABLE #{table.to_sql}
        RENAME CONSTRAINT #{name.name.inspect}
        TO #{new_name.name.inspect};
      SQL
    end

    def invert
      self.class.new(
        **to_h,
        name: (new_name if custom_name?(new_name)),
        to: (name if name != current_name),
      )
    end
  end
end
