# frozen_string_literal: true

module Qi
  # The Action abstraction.
  class Action
    # Initialize an action instance.
    #
    # @param src_square_id [Integer, nil] The source square ID.
    # @param dst_square_id [Integer] The target square ID.
    # @param moved_piece_name [String] The moved piece name.
    # @param captured_piece_name [String, nil] The captured piece name.
    #
    # @example Initialize a promoted bishop action from 43 to 13
    #   new(43, 13, "+B", nil)
    #
    # @see https://developer.sashite.com/specs/portable-action-notation
    def initialize(src_square_id, dst_square_id, moved_piece_name, captured_piece_name = nil)
      @src_square_id = src_square_id
      @dst_square_id = dst_square_id
      @moved_piece_name = moved_piece_name
      @captured_piece_name = captured_piece_name
    end

    # Commit an action to the position.
    #
    # @param in_hand [Array] The list of pieces in hand.
    # @param square [Hash] The index of each piece on the board.
    #
    # @example Commit a Shogi action to the piece set of a position
    #   call(
    #     43, 13, "+B", nil,
    #     in_hand: %w[S r r b g g g g s n n n n p p p p p p p p p p p p p p p p p],
    #     square: {
    #        3 => "s",
    #        4 => "k",
    #        5 => "s",
    #       22 => "+P",
    #       43 => "+B"
    #     }
    #   )
    #   # => {:in_hand=>["S", "r", "r", "b", "g", "g", "g", "g", "s", "n", "n", "n", "n", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p"], :square=>{3=>"s", 4=>"k", 5=>"s", 22=>"+P", 13=>"+B"}}
    #
    # @return [Hash] The next piece set.
    def call(in_hand:, square:)
      in_hand = in_hand.dup
      square = square.dup

      if @src_square_id.nil?
        piece_in_hand_id = in_hand.index(@moved_piece_name)
        in_hand.delete_at(piece_in_hand_id) unless piece_in_hand_id.nil?
      else
        square.delete(@src_square_id)
      end

      square[@dst_square_id] = @moved_piece_name
      in_hand.push(@captured_piece_name) unless @captured_piece_name.nil?

      { in_hand: in_hand, square: square }
    end
  end
end