class WrestlingdevImporter
  ##### Note, the json contains id's for each row in the tables as well as its associations
  ##### this ignores those ids and uses this tournament id and then looks up associations based on name
  ##### and this tournament id
  attr_accessor :import_data
  
  # Support both parameter styles for backward compatibility
  # Old: initialize(tournament, backup)
  # New: initialize(tournament) with import_data setter
  def initialize(tournament, backup = nil)
    @tournament = tournament
    
    # Handle the old style where backup was passed directly
    if backup.present?
      @import_data = JSON.parse(Base64.decode64(backup.backup_data)) rescue nil
    end
  end

  def import
    # Use perform_later which will execute based on centralized adapter config
    WrestlingdevImportJob.perform_later(@tournament, @import_data)
  end

  def import_raw
    @tournament.curently_generating_matches = 1
    @tournament.save
    destroy_all
    parse_data
    @tournament.curently_generating_matches = nil
    @tournament.save
  end

  def destroy_all
    # These depend directly on @tournament and will cascade deletes
    # due to `dependent: :destroy` in the Tournament model
    @tournament.schools.destroy_all # Cascades to Wrestlers, Teampointadjusts, SchoolDelegates
    @tournament.weights.destroy_all # Cascades to Wrestlers, Matches
    @tournament.mats.destroy_all    # Cascades to Matches, MatAssignmentRules
    # Explicitly destroy matches again just in case some aren't linked via mats/weights? Unlikely but safe.
    # Also handles matches linked directly to tournament if that's possible.
    @tournament.matches.destroy_all
    @tournament.mat_assignment_rules.destroy_all # Explicitly destroy rules (might be redundant if Mat cascades)
    @tournament.delegates.destroy_all
    @tournament.tournament_job_statuses.destroy_all
    # Note: Teampointadjusts are deleted via School/Wrestler cascade
  end

  def parse_data
    parse_tournament(@import_data["tournament"]["attributes"])
    parse_schools(@import_data["tournament"]["schools"])
    parse_weights(@import_data["tournament"]["weights"])
    parse_mats(@import_data["tournament"]["mats"])
    parse_wrestlers(@import_data["tournament"]["wrestlers"])
    parse_matches(@import_data["tournament"]["matches"])
    apply_mat_queues
    parse_mat_assignment_rules(@import_data["tournament"]["mat_assignment_rules"])
  end

  def parse_tournament(attributes)
    attributes.except!("id")
    @tournament.update(attributes)
  end

  def parse_schools(schools)
    schools.each do |school_attributes|
      school_attributes.except!("id")
      School.create(school_attributes.merge(tournament_id: @tournament.id))
    end
  end

  def parse_weights(weights)
    weights.each do |weight_attributes|
      weight_attributes.except!("id")
      Weight.create(weight_attributes.merge(tournament_id: @tournament.id))
    end
  end

  def parse_mats(mats)
    @mat_queue_bout_numbers = {}
    mats.each do |mat_attributes|
      mat_name = mat_attributes["name"]
      queue_bout_numbers = mat_attributes["queue_bout_numbers"]
      mat_attributes.except!("id", "queue1", "queue2", "queue3", "queue4", "queue_bout_numbers", "tournament_id")
      Mat.create(mat_attributes.merge(tournament_id: @tournament.id))
      if mat_name && queue_bout_numbers
        @mat_queue_bout_numbers[mat_name] = queue_bout_numbers
      end
    end
  end

  def parse_mat_assignment_rules(mat_assignment_rules)
    mat_assignment_rules.each do |rule_attributes|
      mat_name = rule_attributes.dig("mat", "name")
      mat = Mat.find_by(name: mat_name, tournament_id: @tournament.id)
  
      # Prefer the new "weight_class_maxes" key emitted by backups (human-readable
      # max values). If not present, fall back to the legacy "weight_classes"
      # value which may be a comma-separated string or an array of IDs.
      if rule_attributes.key?("weight_class_maxes") && rule_attributes["weight_class_maxes"].respond_to?(:map)
        new_weight_classes = rule_attributes["weight_class_maxes"].map do |max_value|
          Weight.find_by(max: max_value, tournament_id: @tournament.id)&.id
        end.compact
      elsif rule_attributes["weight_classes"].is_a?(Array)
        # Already an array of IDs
        new_weight_classes = rule_attributes["weight_classes"].map(&:to_i)
      elsif rule_attributes["weight_classes"].is_a?(String)
        # Comma-separated IDs stored in the DB column; split into integers.
        new_weight_classes = rule_attributes["weight_classes"].to_s.split(",").map(&:strip).reject(&:empty?).map(&:to_i)
      else
        new_weight_classes = []
      end
  
      # Extract bracket_positions and rounds (leave as-is; model will coerce if needed)
      bracket_positions = rule_attributes["bracket_positions"]
      rounds = rule_attributes["rounds"]
  
      # Remove any keys we don't want to mass-assign (including both old/new weight keys)
      rule_attributes.except!("id", "mat", "tournament_id", "weight_classes", "weight_class_maxes")
      
      MatAssignmentRule.create(
        rule_attributes.merge(
          tournament_id: @tournament.id,
          mat_id: mat&.id,
          weight_classes: new_weight_classes,
          bracket_positions: bracket_positions,
          rounds: rounds
        )
      )
    end
  end

  def parse_wrestlers(wrestlers)
    wrestlers.each do |wrestler_attributes|
      school = School.find_by(name: wrestler_attributes["school"]["name"], tournament_id: @tournament.id)
      weight = Weight.find_by(max: wrestler_attributes["weight"]["max"], tournament_id: @tournament.id)
      wrestler_attributes.except!("id", "school", "weight")
      Wrestler.create(wrestler_attributes.merge(
        school_id: school&.id,
        weight_id: weight&.id
      ))
    end
  end

  def parse_matches(matches)
    matches.each do |match_attributes|
      next unless match_attributes # Skip if match_attributes is nil

      weight = Weight.find_by(max: match_attributes.dig("weight", "max"), tournament_id: @tournament.id)
      mat = Mat.find_by(name: match_attributes.dig("mat", "name"), tournament_id: @tournament.id)

      w1 = Wrestler.find_by(name: match_attributes["w1_name"], weight_id: weight&.id) if match_attributes["w1_name"]
      w2 = Wrestler.find_by(name: match_attributes["w2_name"], weight_id: weight&.id) if match_attributes["w2_name"]
      winner = Wrestler.find_by(name: match_attributes["winner_name"], weight_id: weight&.id) if match_attributes["winner_name"]

      match_attributes.except!("id", "weight", "mat", "w1_name", "w2_name", "winner_name", "tournament_id")

      Match.create(match_attributes.merge(
        tournament_id: @tournament.id,
        weight_id: weight&.id,
        mat_id: mat&.id,
        w1: w1&.id,
        w2: w2&.id,
        winner_id: winner&.id
      ))
    end
  end

  def apply_mat_queues
    if @mat_queue_bout_numbers.blank?
      Mat.where(tournament_id: @tournament.id).find_each do |mat|
        match_ids = mat.matches.where(finished: [nil, 0]).order(:bout_number).limit(4).pluck(:id)
        mat.update(
          queue1: match_ids[0],
          queue2: match_ids[1],
          queue3: match_ids[2],
          queue4: match_ids[3]
        )
      end
      return
    end

    @mat_queue_bout_numbers.each do |mat_name, bout_numbers|
      mat = Mat.find_by(name: mat_name, tournament_id: @tournament.id)
      next unless mat

      matches = Array(bout_numbers).map do |bout_number|
        Match.find_by(bout_number: bout_number, tournament_id: @tournament.id)
      end

      mat.update(
        queue1: matches[0]&.id,
        queue2: matches[1]&.id,
        queue3: matches[2]&.id,
        queue4: matches[3]&.id
      )

      matches.compact.each do |match|
        match.update(mat_id: mat.id)
      end
    end

    Mat.where(tournament_id: @tournament.id)
       .where(queue1: nil, queue2: nil, queue3: nil, queue4: nil)
       .find_each do |mat|
      match_ids = mat.matches.where(finished: [nil, 0]).order(:bout_number).limit(4).pluck(:id)
      mat.update(
        queue1: match_ids[0],
        queue2: match_ids[1],
        queue3: match_ids[2],
        queue4: match_ids[3]
      )
    end
  end
end
