class Game < ApplicationRecord
  has_many :turns, dependent: :destroy
  has_many :participants, dependent: :destroy
  has_many :users, through: :participants
  has_many :boards, dependent: :destroy
  has_one :latest_turn, -> { order(number: :desc) }, class_name: "Turn"

  # パスワード保護
  has_secure_password :password, validations: false

  # バリデーション
  validates :status, inclusion: {
    in: %w[recruiting power_selection in_progress finished cancelled]
  }
  validates :auto_order_mode, inclusion: { in: %w[hold random] }
  validates :participants_count,
    numericality: { greater_than_or_equal_to: 2, less_than_or_equal_to: 7 },
    unless: :is_solo_mode?

  # ハウスルールバリデーション
  validates :year_limit,
    numericality: { only_integer: true, greater_than_or_equal_to: 1901, less_than_or_equal_to: 1999 },
    allow_nil: true
  validates :victory_sc_count,
    numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 34 }
  validates :scoring_system, inclusion: { in: %w[none sc_count sc_ratio dss sos] }

  # ターンスケジュールバリデーション
  validate :validate_turn_schedule

  # コールバック
  after_create :create_global_board

  # ヘルパーメソッド
  def password_protected?
    password_digest.present?
  end

  def solo_mode?
    is_solo_mode
  end

  def administrator
    participants.find_by(is_administrator: true)&.user
  end

  def available_powers
    assigned_powers = participants.where.not(power: nil).pluck(:power)
    %w[AUSTRIA ENGLAND FRANCE GERMANY ITALY RUSSIA TURKEY] - assigned_powers
  end

  def all_powers_assigned?
    participants.where(power: nil).empty? &&
    participants.count == participants_count
  end

  def all_orders_submitted?
    participants.where(power: nil).empty? &&
    participants.all?(&:orders_submitted)
  end

  def unassigned_powers
    all_powers = %w[AUSTRIA ENGLAND FRANCE GERMANY ITALY RUSSIA TURKEY]
    assigned_powers = participants.where.not(power: nil).pluck(:power)
    all_powers - assigned_powers
  end

  # ターンスケジュール関連メソッド

  def auto_turn?
    turn_schedule.present?
  end

  # 次のデッドラインを計算（日本時間基準）
  def calculate_next_deadline
    return nil unless turn_schedule.present?

    hours = turn_schedule.split(",").map(&:strip).map(&:to_i).sort
    now = Time.current.in_time_zone("Asia/Tokyo")

    # 今日の残りの時間枠を探す（JST基準）
    next_time = hours.map { |h| now.beginning_of_day + h.hours }
                     .find { |t| t > now }

    # 今日の枠がなければ翌日の最初の枠
    next_time || (now.beginning_of_day + 1.day + hours.first.hours)
  end

  # スケジュール表示用
  def schedule_display
    return "手動" unless turn_schedule.present?
    hours = turn_schedule.split(",").map(&:strip)
    "毎日 " + hours.map { |h| "#{h}時" }.join("・")
  end

  # ハウスルール関連メソッド

  # 年数制限チェック: フェーズ名から年を抽出し、year_limitを超えているか判定
  def year_limit_reached?(phase_name)
    return false unless year_limit.present? && phase_name.present?

    # フェーズ名の例: "S1901M", "F1910R", "W1901A"
    year_match = phase_name.match(/[SFW](\d{4})[MRA]/)
    return false unless year_match

    year_match[1].to_i > year_limit
  end

  # ソロ勝利判定: いずれかの国のSC数がvictory_sc_count以上か
  def solo_victory?(game_state)
    centers = game_state&.dig("centers") || {}
    centers.any? { |_power, scs| scs.size >= victory_sc_count }
  end

  # ソロ勝利した国を返す
  def solo_victory_power(game_state)
    centers = game_state&.dig("centers") || {}
    centers.find { |_power, scs| scs.size >= victory_sc_count }&.first
  end

  # スコア計算
  def calculate_scores(game_state)
    return {} if scoring_system == "none"

    centers = game_state&.dig("centers") || {}
    total_scs = centers.values.flatten.size
    alive_count = centers.count { |_power, scs| scs.any? }

    case scoring_system
    when "sc_count"
      # 単純SC数
      centers.transform_values { |scs| scs.size }
    when "sc_ratio"
      # SC比率（%）
      centers.transform_values { |scs| total_scs > 0 ? (scs.size.to_f / total_scs * 100).round(1) : 0 }
    when "dss"
      # Draw Size Scoring: 生存国で均等分割
      centers.transform_values { |scs| scs.any? ? (100.0 / alive_count).round(1) : 0 }
    when "sos"
      # Sum of Squares
      sum_of_squares = centers.values.sum { |scs| scs.size ** 2 }.to_f
      centers.transform_values { |scs| sum_of_squares > 0 ? ((scs.size ** 2) / sum_of_squares * 100).round(1) : 0 }
    else
      {}
    end
  end

  # スコアリング方式の日本語名
  def scoring_system_name
    case scoring_system
    when "none" then "なし"
    when "sc_count" then "SC数"
    when "sc_ratio" then "SC比率"
    when "dss" then "DSS（均等分割）"
    when "sos" then "SoS（二乗和）"
    else scoring_system
    end
  end

  private

  def validate_turn_schedule
    return if turn_schedule.blank?

    hours = turn_schedule.split(",").map(&:strip)
    unless hours.all? { |h| h.match?(/\A\d{1,2}\z/) && h.to_i.between?(0, 23) }
      errors.add(:turn_schedule, "は0〜23の数値をカンマ区切りで入力してください（例: 0,18）")
    end
  end

  def create_global_board
    boards.create!(board_type: "global", is_public: true)
  end
end
