--
-- 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 FUNCTION create_table_kyc_targets(
  IN partition_suffix TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
  my_rec RECORD;
  my_payto TEXT;
  my_is_wallet BOOL;
  wtc CURSOR FOR
   SELECT
     access_token
    ,target_pub
    ,h_normalized_payto
    ,aml_program_lock_timeout
    ,payto_uri
     FROM exchange.wire_targets;
BEGIN
  PERFORM create_partitioned_table(
    'CREATE TABLE %I'
      '(kyc_target_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY'
      ',h_normalized_payto BYTEA PRIMARY KEY CHECK(LENGTH(h_normalized_payto)=32)'
      ',access_token BYTEA CHECK(LENGTH(access_token)=32)'
      ' DEFAULT random_bytea(32)'
      ',target_pub BYTEA CHECK(LENGTH(target_pub)=32) DEFAULT NULL'
      ',aml_program_lock_timeout INT8 DEFAULT NULL'
      ',is_wallet BOOL'
    ') %s ;'
    ,'kyc_targets'
    ,'PARTITION BY HASH (h_normalized_payto)'
    ,partition_suffix
  );
  PERFORM comment_partitioned_table(
     'All identities for KYC purposes based on normalized payto URIs'
    ,'kyc_targets'
    ,partition_suffix
  );
  PERFORM comment_partitioned_column(
     'high-entropy random value that is used as a bearer token used to authenticate access to the KYC SPA and its state (without requiring a signature)'
    ,'access_token'
    ,'kyc_targets'
    ,NULL
  );
  PERFORM comment_partitioned_column(
     'Public key of a merchant instance or reserve to authenticate access; NULL if KYC is not allowed for the account (if there was no incoming KYC wire transfer yet); updated, thus NOT available to the auditor'
    ,'target_pub'
    ,'kyc_targets'
    ,NULL
  );
  PERFORM comment_partitioned_column(
     'hash over the normalized payto URI for this account; used for KYC operations'
    ,'h_normalized_payto'
    ,'kyc_targets'
    ,NULL
  );
  PERFORM comment_partitioned_column(
     'If non-NULL, an AML program should be running and it holds a lock on this account, thus other AML programs should not be started concurrently. Given the possibility of crashes, the lock automatically expires at the time value given in this column. At that time, the lock can be considered stale.'
    ,'aml_program_lock_timeout'
    ,'kyc_targets'
    ,NULL
  );
  PERFORM comment_partitioned_column(
     'True if this KYC account is for a wallet, false if it is for a bank account'
    ,'is_wallet'
    ,'kyc_targets'
    ,NULL
  );

  -- Migrate existing entries. We may have multiple for
  -- the same account, which is a historic bug (#10003)
  -- we are implicitly fixing here via "ON CONFLICT
  -- DO NOTHING" which ensures that moving forward we
  -- have a unique access token per KYC account.
  FOR my_rec IN wtc
  LOOP
    my_payto = my_rec.payto_uri;
    my_is_wallet
      = (LOWER (SUBSTRING (my_payto, 22)) =
         'payto://taler-reserve/') OR
        (LOWER (SUBSTRING (my_payto, 27)) =
         'payto://taler-reserve-http/');
    INSERT INTO kyc_targets
      (h_normalized_payto
      ,access_token
      ,target_pub
      ,aml_program_lock_timeout
      ,is_wallet
      ) VALUES (
       my_rec.h_normalized_payto
      ,my_rec.access_token
      ,my_rec.target_pub
      ,my_rec.aml_program_lock_timeout
      ,my_is_wallet
      )
      ON CONFLICT DO NOTHING;
  END LOOP;
END $$;


CREATE FUNCTION constrain_table_kyc_targets(
  IN partition_suffix TEXT
)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
  table_name TEXT DEFAULT 'kyc_targets';
BEGIN
  table_name = concat_ws('_', table_name, partition_suffix);
  EXECUTE FORMAT (
    'ALTER TABLE ' || table_name ||
    ' ADD CONSTRAINT ' || table_name || '_kyc_target_serial_id_key'
    ' UNIQUE (kyc_target_serial_id)'
  );
  EXECUTE FORMAT (
    'ALTER TABLE ' || table_name ||
    ' ADD CONSTRAINT ' || table_name || '_kyc_target_access_token_unique'
    ' UNIQUE (access_token)'
  );
END
$$;


INSERT INTO exchange_tables
    (name
    ,version
    ,action
    ,partitioned
    ,by_range)
  VALUES
    ('kyc_targets'
    ,'exchange-0003'
    ,'create'
    ,TRUE
    ,FALSE),
    ('kyc_targets'
    ,'exchange-0003'
    ,'constrain'
    ,TRUE
    ,FALSE);
