--
-- This file is part of TALER
-- Copyright (C) 2024-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/>

BEGIN;
SET search_path TO libeufin_bank;

CREATE OR REPLACE FUNCTION cashout_link() 
RETURNS trigger 
LANGUAGE plpgsql AS $$
  DECLARE
    now_date INT8;
    payto_uri TEXT;
  BEGIN
    IF NEW.local_transaction IS NOT NULL THEN
      SELECT transaction_date INTO now_date
        FROM libeufin_bank.bank_account_transactions
        WHERE bank_transaction_id = NEW.local_transaction;
      SELECT cashout_payto INTO payto_uri
        FROM libeufin_bank.bank_accounts
          JOIN libeufin_bank.customers ON customer_id=owning_customer_id
        WHERE bank_account_id=NEW.bank_account;
      INSERT INTO libeufin_nexus.initiated_outgoing_transactions (
          amount
          ,subject
          ,credit_payto
          ,initiation_time
          ,end_to_end_id
      ) VALUES (
          ((NEW.amount_credit).val, (NEW.amount_credit).frac)::libeufin_nexus.taler_amount
          ,NEW.subject
          ,payto_uri
          ,now_date
          -- use gen_random_uuid to get some randomness
          -- remove all - characters as they are not random
          -- capitalise the UUID as some bank may still be case sensitive
          -- end with 34 random chars which is valid for EBICS (max 35 chars)
          ,upper(replace(gen_random_uuid()::text, '-', ''))
      );
    END IF;
    RETURN NEW;
  END;
$$;

CREATE OR REPLACE TRIGGER cashout_link BEFORE INSERT OR UPDATE ON libeufin_bank.cashout_operations
    FOR EACH ROW EXECUTE FUNCTION cashout_link();

CREATE OR REPLACE FUNCTION cashin_link() 
RETURNS trigger 
LANGUAGE plpgsql AS $$
  DECLARE
    now_date INT8;
    local_amount libeufin_bank.taler_amount;
    local_subject TEXT;
    too_small BOOLEAN;
    balance_insufficient BOOLEAN;
    no_account BOOLEAN;
    no_config BOOLEAN;
  BEGIN
    -- Only reserve transaction triggers cashin
    IF NEW.type != 'reserve' THEN
      RETURN NEW;
    END IF;

    SELECT (amount).val, (amount).frac, subject, execution_time
      INTO local_amount.val, local_amount.frac, local_subject, now_date
      FROM libeufin_nexus.incoming_transactions
      WHERE incoming_transaction_id = NEW.incoming_transaction_id;
    SET search_path TO libeufin_bank;
    SELECT out_too_small, out_balance_insufficient, out_no_account, out_no_config
      INTO too_small, balance_insufficient, no_account, no_config
      FROM libeufin_bank.cashin(now_date, NEW.metadata, local_amount, local_subject);
    SET search_path TO libeufin_nexus;

    -- Bounce on soft failures
    IF too_small THEN
      -- TODO bounce fees ?
      PERFORM bounce_incoming(
         NEW.incoming_transaction_id
        ,((local_amount).val, (local_amount).frac)::taler_amount
        -- use gen_random_uuid to get some randomness
        -- remove all - characters as they are not random
        -- capitalise the UUID as some bank may still be case sensitive
        -- end with 34 random chars which is valid for EBICS (max 35 chars)
        ,upper(replace(gen_random_uuid()::text, '-', ''))
        ,now_date
      );
      RETURN NULL;
    END IF;

    -- Error on hard failures
    IF no_config THEN
      RAISE EXCEPTION 'cashin currency conversion failed: missing conversion rates';
    END IF;
    IF no_account THEN
      RAISE EXCEPTION 'cashin failed: missing exchange account';
    END IF;
    IF balance_insufficient THEN
      RAISE EXCEPTION 'cashin failed: admin balance insufficient';
    END IF;

    RETURN NEW;
  END;
$$;

CREATE OR REPLACE TRIGGER cashin_link BEFORE INSERT ON libeufin_nexus.talerable_incoming_transactions
    FOR EACH ROW EXECUTE FUNCTION cashin_link();

COMMIT;