--
-- This file is part of TALER
-- Copyright (C) 2014--2025 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 3, or (at your option) any later version.
--
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
--

CREATE OR REPLACE PROCEDURE exchange_do_main_gc(
  IN in_ancient_date INT8,
  IN in_now INT8)
LANGUAGE plpgsql
AS $$
DECLARE
  coin_min INT8; -- minimum known_coin still alive
  batch_deposit_min INT8; -- minimum deposit still alive
  withdraw_min INT8; -- minimum withdraw still alive
  denom_min INT8; -- minimum denomination still alive
BEGIN

DELETE FROM prewire
  WHERE finished=TRUE;

DELETE FROM wire_fee
  WHERE end_date < in_ancient_date;

DELETE FROM refresh
  WHERE execution_date < in_ancient_date;

DELETE FROM kycauths_in
  WHERE execution_date < in_ancient_date;

DELETE FROM reserves_in
  WHERE execution_date < in_ancient_date;

DELETE FROM batch_deposits
  WHERE wire_deadline < in_ancient_date;

-- FIXME: use closing fee as threshold?
DELETE FROM withdraw
  WHERE reserve_pub IN (
    SELECT reserve_pub
      FROM reserves
     WHERE gc_date < in_now
       AND current_balance = (0, 0));

DELETE FROM reserves_close
  WHERE reserve_pub IN (
    SELECT reserve_pub
      FROM reserves
     WHERE gc_date < in_now
       AND current_balance = (0, 0));

SELECT withdraw_id
  INTO withdraw_min
  FROM withdraw
  ORDER BY withdraw_id ASC
  LIMIT 1;

DELETE FROM recoup
  WHERE withdraw_id < withdraw_min;

DELETE FROM reserves
  WHERE gc_date < in_now
    AND current_balance = (0, 0);

-- FIXME: this query will be horribly slow;
-- need to find another way to formulate it...
DELETE FROM denominations
  WHERE expire_legal < in_now
    AND denominations_serial NOT IN
      (SELECT DISTINCT UNNEST(denom_serials)
         FROM withdraw)
    AND denominations_serial NOT IN
      (SELECT DISTINCT denominations_serial
         FROM known_coins
        WHERE coin_pub IN
          (SELECT DISTINCT coin_pub
             FROM recoup))
    AND denominations_serial NOT IN
      (SELECT DISTINCT denominations_serial
         FROM known_coins
        WHERE coin_pub IN
          (SELECT DISTINCT coin_pub
             FROM recoup_refresh));

DELETE FROM recoup_refresh
  WHERE known_coin_id < coin_min;

SELECT known_coin_id
  INTO coin_min
  FROM known_coins
  ORDER BY known_coin_id ASC
  LIMIT 1;

SELECT batch_deposit_serial_id
  INTO batch_deposit_min
  FROM coin_deposits
  ORDER BY batch_deposit_serial_id ASC
  LIMIT 1;

DELETE FROM refunds
  WHERE batch_deposit_serial_id < batch_deposit_min;
DELETE FROM aggregation_tracking
  WHERE batch_deposit_serial_id < batch_deposit_min;
DELETE FROM coin_deposits
  WHERE batch_deposit_serial_id < batch_deposit_min;

SELECT denominations_serial
  INTO denom_min
  FROM denominations
  ORDER BY denominations_serial ASC
  LIMIT 1;

DELETE FROM cs_nonce_locks
  WHERE max_denomination_serial <= denom_min;

END $$;
