# frozen_string_literal: true

require 'dotenv/load'
require 'time'

def record_all_cassettes(cassette_dir)
  FileUtils.rm_rf(cassette_dir)
  FileUtils.mkdir_p(cassette_dir)

  puts 'Recording cassettes for all providers...'
  run_tests
  puts 'Done recording. Please review the new cassettes.'
end

def record_for_providers(providers, cassette_dir)
  all_providers = RubyLLM::Provider.providers.keys.map(&:to_s)

  if providers.empty?
    puts "Please specify providers or 'all'. Example: rake vcr:record[openai,anthropic]"
    puts "Available providers: #{all_providers.join(', ')}"
    return
  end

  invalid_providers = providers - all_providers
  if invalid_providers.any?
    puts "Invalid providers: #{invalid_providers.join(', ')}"
    puts "Available providers: #{all_providers.join(', ')}"
    return
  end

  cassettes_to_delete = find_matching_cassettes(cassette_dir, providers)

  if cassettes_to_delete.empty?
    puts 'No cassettes found for the specified providers.'
    puts 'Running tests to record new cassettes...'
  else
    delete_cassettes(cassettes_to_delete)
    puts "\nRunning tests to record new cassettes..."
  end

  run_tests

  puts "\nDone recording cassettes for #{providers.join(', ')}."
  puts 'Please review the updated cassettes for sensitive information.'
end

def find_matching_cassettes(dir, providers)
  cassettes = []

  Dir.glob("#{dir}/**/*.yml").each do |file|
    basename = File.basename(file)

    providers.each do |provider|
      next unless basename =~ /^[^_]*_#{provider}_/ || # For first section like "chat_openai_"
                  basename =~ /_#{provider}_[^_]+_/    # For middle sections like "_openai_gpt4_"

      cassettes << file
      break
    end
  end

  cassettes
end

def delete_cassettes(cassettes)
  puts "Deleting #{cassettes.size} cassettes for re-recording:"
  cassettes.each do |file|
    puts "  - #{File.basename(file)}"
    File.delete(file)
  end
end

def run_tests
  run_test_queue_rspec || abort('Tests failed')
end

def retimestamp_cassettes(cassette_dir)
  timestamp = Time.now.utc.httpdate
  updated_files = 0
  updated_entries = 0

  Dir.glob("#{cassette_dir}/**/*.yml").each do |file|
    content = File.read(file)
    replacements = 0

    updated = content.gsub(/^(\s*recorded_at:\s*).+$/) do
      replacements += 1
      "#{Regexp.last_match(1)}#{timestamp}"
    end

    next if replacements.zero?

    File.write(file, updated)
    updated_files += 1
    updated_entries += replacements
  end

  puts "Updated #{updated_entries} recorded_at entries in #{updated_files} cassette files."
  puts "New recorded_at value: #{timestamp}"
end

namespace :vcr do
  desc 'Record VCR cassettes (rake vcr:record[all] or vcr:record[openai,anthropic])'
  task :record, :providers do |_, args|
    require 'fileutils'
    require 'ruby_llm'

    providers = args.extras.unshift(args[:providers]).compact.map(&:downcase)
    cassette_dir = 'spec/fixtures/vcr_cassettes'
    FileUtils.mkdir_p(cassette_dir)

    if providers.include?('all')
      record_all_cassettes(cassette_dir)
    else
      record_for_providers(providers, cassette_dir)
    end
  end

  desc 'Update recorded_at timestamps for all cassette entries'
  task :retimestamp do
    cassette_dir = 'spec/fixtures/vcr_cassettes'
    retimestamp_cassettes(cassette_dir)
  end
end
