# frozen_string_literal: true

# canonical.rb - Loads canonical seed data from CSV files into the database.
#
# This file is used to load canonical data for various models from CSV files
# located in db/seed/test. For models that reference other models by fixed IDs
# (e.g. Job, Guidebook, etc.), use the `use_id: true` option to preserve the CSV
# provided IDs (so that inter-model references remain correct).
#
# @example
#   load_csv_for(Character, 'characters_test.csv', :granblue_id)
#
#   # For objects that need to preserve the CSV "id" column:
#   load_csv_for(Job, 'jobs_test.csv', :granblue_id, use_id: true)
#
require 'csv'

##
# Processes specified columns in an attributes hash to booleans.
#
# @param attrs [Hash] The attributes hash.
# @param columns [Array<Symbol>] The list of columns to cast to boolean.
def process_booleans(attrs, columns)
  columns.each do |col|
    next unless attrs.key?(col) && attrs[col].present?
    # Use ActiveModel::Type::Boolean to cast the value.
    attrs[col] = ActiveModel::Type::Boolean.new.cast(attrs[col])
  end
end

##
# Processes specified columns in an attributes hash to dates.
#
# @param attrs [Hash] The attributes hash.
# @param columns [Array<Symbol>] The list of columns to parse as dates.
def process_dates(attrs, columns)
  columns.each do |col|
    next unless attrs.key?(col) && attrs[col].present?
    # Parse the date, or assign nil if parsing fails.
    attrs[col] = Date.parse(attrs[col]) rescue nil
  end
end

##
# Loads CSV data for the given model class.
#
# Reads a CSV file from the db/seed/test directory and uses the given unique_key
# to determine whether a record already exists. If the record exists, its attributes
# are not overwritten; otherwise, a new record is created.
#
# @param model_class [Class] The ActiveRecord model class to load data for.
# @param csv_filename [String] The CSV filename (located in db/seed/test).
# @param unique_key [Symbol] The attribute used to uniquely identify a record (default: :granblue_id).
# @param use_id [Boolean] If true, preserves the CSV id field instead of removing it (default: false).
#
# @return [void]
def load_csv_for(model_class, csv_filename, unique_key = :granblue_id, use_id: false)
  csv_file = Rails.root.join('db', 'seed', 'test', csv_filename)
  # puts "Loading #{model_class.name} data from #{csv_file}..."

  CSV.foreach(csv_file, headers: true) do |row|
    # Convert CSV row to a hash with symbolized keys.
    attrs = row.to_hash.symbolize_keys

    # Process known boolean columns.
    process_booleans(attrs, %i[flb ulb subaura limit transcendence])
    # Process known date columns. Extend this list as needed.
    process_dates(attrs, %i[release_date flb_date ulb_date transcendence_date created_at])

    # Clean up attribute values: trim whitespace and convert empty strings to nil.
    attrs.each { |k, v| attrs[k] = nil if v.is_a?(String) && v.strip.empty? }

    # Remove the :id attribute unless we want to preserve it (for fixed canonical IDs).
    attrs.except!(:id) unless use_id

    # Skip records with missing associations (for test data)
    if model_class == WeaponAwakening
      next unless Weapon.exists?(attrs[:weapon_id]) && Awakening.exists?(attrs[:awakening_id])
    end

    # Find or create the record based on the unique key.
    record = model_class.find_or_create_by!(unique_key => attrs[unique_key]) do |r|
      # Assign all attributes except the unique_key.
      r.assign_attributes(attrs.except(unique_key))
    end

    # puts "Loaded #{model_class.name}: #{record.public_send(unique_key)}"
  end
end

# Load canonical data for core models.
# Load weapon_series first since weapons depend on it
load_csv_for(WeaponSeries, 'weapon_series_test.csv', :id, use_id: true)
load_csv_for(Awakening, 'awakenings_test.csv', :id, use_id: true)
load_csv_for(Summon, 'summons_test.csv', :id, use_id: true)
load_csv_for(Weapon, 'weapons_test.csv', :id, use_id: true)
load_csv_for(Character, 'characters_test.csv', :id, use_id: true)

# Load additional canonical data that require preserving the provided IDs.
load_csv_for(Job, 'jobs_test.csv', :id, use_id: true)
load_csv_for(Guidebook, 'guidebooks_test.csv', :id, use_id: true)
load_csv_for(JobAccessory, 'job_accessories_test.csv', :id, use_id: true)
load_csv_for(JobSkill, 'job_skills_test.csv', :id, use_id: true)
load_csv_for(WeaponAwakening, 'weapon_awakenings_test.csv', :id, use_id: true)
load_csv_for(WeaponKey, 'weapon_keys_test.csv', :id, use_id: true)
