# frozen_string_literal: true

# This migration cleans up orphaned balance records that have a currency different
# from their account's current currency. This can happen when linked accounts
# (SimpleFIN, Lunchflow, Enable Banking, Plaid) were created with an initial sync
# before the correct currency was known from the provider.
#
# The fix in Account.create_and_sync with skip_initial_sync: true prevents this
# going forward, but existing data needs to be cleaned up.
class CleanupOrphanedCurrencyBalances < ActiveRecord::Migration[7.2]
  def up
    # Skip in test environment with empty database (CI)
    return say "Skipping in test environment - no data to clean" if Rails.env.test? && account_count.zero?

    # First, identify affected accounts for logging
    affected_accounts = execute(<<~SQL).to_a
      SELECT DISTINCT
        a.id,
        a.name,
        a.currency as account_currency,
        b.currency as orphaned_currency,
        COUNT(b.id) as orphaned_balance_count
      FROM accounts a
      JOIN balances b ON a.id = b.account_id
      WHERE b.currency != a.currency
        AND (
          a.simplefin_account_id IS NOT NULL
          OR a.plaid_account_id IS NOT NULL
          OR EXISTS (SELECT 1 FROM account_providers WHERE account_id = a.id)
        )
      GROUP BY a.id, a.name, a.currency, b.currency
      ORDER BY a.name
    SQL

    if affected_accounts.any?
      say "Found #{affected_accounts.size} account-currency combinations with orphaned balances:"
      affected_accounts.each do |row|
        say "  - #{row['name']}: #{row['orphaned_balance_count']} balances in #{row['orphaned_currency']} (account is #{row['account_currency']})"
      end

      # Delete orphaned balances where currency doesn't match account currency
      # Only for linked accounts (provider-connected accounts)
      execute(<<~SQL)
        DELETE FROM balances
        WHERE id IN (
          SELECT b.id
          FROM balances b
          JOIN accounts a ON b.account_id = a.id
          WHERE b.currency != a.currency
            AND (
              a.simplefin_account_id IS NOT NULL
              OR a.plaid_account_id IS NOT NULL
              OR EXISTS (SELECT 1 FROM account_providers WHERE account_id = a.id)
            )
        )
      SQL

      say "Deleted orphaned balances from linked accounts"

      # Get unique account IDs that need re-sync
      account_ids = affected_accounts.map { |row| row["id"] }.uniq

      # Schedule re-sync for affected accounts to regenerate correct balances
      # Only if Account model is available and responds to sync_later
      if defined?(Account) && Account.respond_to?(:where)
        say "Scheduling re-sync for #{account_ids.size} affected accounts..."
        Account.where(id: account_ids).find_each do |account|
          account.sync_later if account.respond_to?(:sync_later)
        end
        say "Scheduled re-sync for #{account_ids.size} affected accounts"
      else
        say "Skipping re-sync scheduling (Account model not available)"
        say "Please manually sync affected accounts: #{account_ids.join(', ')}"
      end
    else
      say "No orphaned currency balances found - database is clean"
    end
  end

  def down
    say "This migration cannot be fully reversed."
    say "The deleted balances will be regenerated by the scheduled syncs."
    say "If syncs haven't run yet, you may need to manually trigger them."
  end

  private

    def account_count
      execute("SELECT COUNT(*) FROM accounts").first["count"].to_i
    rescue
      0
    end
end
