#!/bin/bash
# This file is in the public domain.

set -eu

echo -n "Test if OpenSSL is available..."
openssl &>/dev/null || (echo " No!" ; exit 77 )
echo " OK"

taler-merchant-dbinit -r -c test-merchantdb-postgres.conf

# Generate random BYTEA values for testing
WTID=$(openssl rand -hex 32)
EXCHANGE_PUB=$(openssl rand -hex 32)
EXCHANGE_SIG=$(openssl rand -hex 64)
COIN_PUB=$(openssl rand -hex 32)

# Generate valid BYTEA values
MERCHANT_PUB=$(openssl rand -hex 32)
AUTH_HASH=$(openssl rand -hex 64)
AUTH_SALT=$(openssl rand -hex 32)

# Define other parameters
INSTANCE_ID="test-merchant"
EXCHANGE_URL="http://example.com/exchange"
PAYTO_URI="payto://example.com/account"
EXECUTION_TIME=$(date +%s)

# Generate taler_amount_currency values
TOTAL_AMOUNT="ROW(100, 0, 'USD')::taler_amount_currency"
WIRE_FEE="ROW(1, 0, 'USD')::taler_amount_currency"

# Generate arrays for taler_amount_currency and BYTEA
# Generate arrays for taler_amount_currency and BYTEA
COIN_VALUES="ARRAY[ROW(10, 0, 'USD')::taler_amount_currency, ROW(20, 0, 'USD')::taler_amount_currency, ROW(30, 0, 'USD')::taler_amount_currency]::taler_amount_currency[]"
DEPOSIT_FEES="ARRAY[ROW(1, 0, 'USD')::taler_amount_currency, ROW(2, 50000000, 'USD')::taler_amount_currency, ROW(3, 25000000, 'USD')::taler_amount_currency]::taler_amount_currency[]"
COIN_PUBS="ARRAY[decode('$COIN_PUB', 'hex'), decode('$(openssl rand -hex 32)', 'hex'), decode('$(openssl rand -hex 32)', 'hex')]::BYTEA[]"
CONTRACT_TERMS="ARRAY[decode('$(openssl rand -hex 32)', 'hex'), decode('$(openssl rand -hex 32)', 'hex'), decode('$(openssl rand -hex 32)', 'hex')]::BYTEA[]"

# Create the merchant database
echo "SET search_path TO merchant;
      INSERT INTO merchant_instances (
          merchant_serial,
          merchant_name,
          merchant_id,
          address,
          jurisdiction,
          default_wire_transfer_delay,
          default_pay_delay,
          merchant_pub,
          auth_hash,
          auth_salt
      ) VALUES (
          1,
          'Test Merchant',
          'test-merchant',
          '{"city":"TestCity"}',
          '{"country":"TestCountry"}',
          3600,
          3600,
          decode('$MERCHANT_PUB', 'hex'),
          decode('$AUTH_HASH', 'hex'),
          decode('$AUTH_SALT', 'hex')
      );" | psql talercheck

# Create the webhooks
echo "SET search_path TO merchant;
      INSERT INTO merchant_webhook (merchant_serial, webhook_id, event_type, url, http_method, body_template)
      VALUES
      (1, 'category_added_hook', 'category_added', 'http://example.com/category_added', 'POST', '{"event":"{{ webhook_type }}"}'),
      (1, 'category_updated_hook', 'category_updated', 'http://example.com/category_updated', 'POST', '{"event":"{{ webhook_type }}"}'),
      (1, 'category_deleted_hook', 'category_deleted', 'http://example.com/category_deleted', 'POST', '{"event":"{{ webhook_type }}"}'),
      (1, 'inventory_added_hook', 'inventory_added', 'http://example.com/inventory_added', 'POST', '{"event":"{{ webhook_type }}"}'),
      (1, 'inventory_updated_hook', 'inventory_updated', 'http://example.com/inventory_updated', 'POST', '{"event":"{{ webhook_type }}"}'),
      (1, 'inventory_deleted_hook', 'inventory_deleted', 'http://example.com/inventory_deleted', 'POST', '{"event":"{{ webhook_type }}"}'),
      (1, 'order_settled_hook', 'order_settled', 'http://example.com/order_settled', 'POST', '{"event":"{{ webhook_type }}"}');" | psql talercheck

# Create the category
echo "SET search_path TO merchant;
      INSERT INTO merchant_categories (merchant_serial, category_name, category_name_i18n)
      VALUES (1, 'Test Category', '{"en":"Test Category"}');" | psql talercheck

# Update the category
echo "SET search_path TO merchant;
      UPDATE merchant_categories
      SET category_name = 'Updated Category'
      WHERE category_name = 'Test Category';" | psql talercheck

# Delete the category
echo "SET search_path TO merchant;
      DELETE FROM merchant_categories
      WHERE category_name = 'Updated Category';" | psql talercheck

# Add product to inventory
echo "SET search_path TO merchant;
      INSERT INTO merchant_inventory (merchant_serial, product_id, description, description_i18n, unit, image, taxes, price, total_stock, address, next_restock)
      VALUES
      (1, 'test-product', 'Test Product', '{"en":"Test Product"}', 'unit', 'image-data-url', '[]', ROW(10, 0, 'USD'), 100, '{"city":"TestCity"}', 0);" | psql talercheck

# Update product in inventory
echo "SET search_path TO merchant;
      UPDATE merchant_inventory
      SET description = 'Updated Test Product'
      WHERE product_id = 'test-product';" | psql talercheck

# Delete product from inventory
echo "SET search_path TO merchant;
      DELETE FROM merchant_inventory
      WHERE product_id = 'test-product';" | psql talercheck

# Create the merchant account
echo "SET search_path TO merchant;
      INSERT INTO merchant_accounts (
          merchant_serial,
          h_wire,
          salt,
          credit_facade_url,
          credit_facade_credentials,
          last_bank_serial,
          payto_uri,
          active
      ) VALUES (
          1,
          decode('$(openssl rand -hex 64)', 'hex'),
          decode('$(openssl rand -hex 16)', 'hex'),
          'http://example.com/credit',
          '{"key":"value"}',
          0,
          '$PAYTO_URI',
          TRUE
      );" | psql talercheck

# Create the merchant transfer
echo "SET search_path TO merchant;
      INSERT INTO merchant_transfers (
          credit_serial,
          exchange_url,
          wtid,
          credit_amount,
          account_serial
      ) VALUES (
          1,
          'http://example.com/exchange',
          decode('$WTID', 'hex'),
          ROW(100, 0, 'USD')::taler_amount_currency,
          1
      );" | psql talercheck

# Create the exchange signing key
echo "SET search_path TO merchant;
      INSERT INTO merchant_exchange_signing_keys (
          master_pub,
          exchange_pub,
          start_date,
          expire_date,
          end_date,
          master_sig
      ) VALUES (
          decode('$(openssl rand -hex 32)', 'hex'),
          decode('$EXCHANGE_PUB', 'hex'),
          EXTRACT(EPOCH FROM NOW()),
          EXTRACT(EPOCH FROM NOW()) + 3600,
          EXTRACT(EPOCH FROM NOW()) + 7200,
          decode('$(openssl rand -hex 64)', 'hex')
      );" | psql talercheck

# Create the merchant_contract_terms
echo "SET search_path TO merchant;
      INSERT INTO merchant_contract_terms (
          order_serial,
          merchant_serial,
          order_id,
          contract_terms,
          wallet_data,
          h_contract_terms,
          creation_time,
          pay_deadline,
          refund_deadline,
          paid,
          wired,
          fulfillment_url,
          session_id,
          pos_key,
          pos_algorithm,
          claim_token
      ) VALUES (
          1001,
          1,
          'order-1234',
          decode('$(openssl rand -hex 64)', 'hex'),
          '{"wallet":"test"}',
          decode('$(openssl rand -hex 64)', 'hex'),
          EXTRACT(EPOCH FROM NOW()),
          EXTRACT(EPOCH FROM NOW()) + 3600,
          EXTRACT(EPOCH FROM NOW()) + 7200,
          FALSE,
          FALSE,
          'http://example.com/fulfillment',
          '',
          NULL,
          0,
          decode('$(openssl rand -hex 16)', 'hex')
      );" | psql talercheck

echo "SET search_path TO merchant;
      INSERT INTO merchant_deposit_confirmations (
          order_serial,
          deposit_timestamp,
          exchange_url,
          total_without_fee,
          wire_fee,
          signkey_serial,
          exchange_sig,
          account_serial,
          wire_pending
      ) VALUES (
          1001,
          EXTRACT(EPOCH FROM NOW()),
          '$EXCHANGE_URL',
          ROW(90, 0, 'USD')::taler_amount_currency,
          ROW(10, 0, 'USD')::taler_amount_currency,
          1,
          decode('$EXCHANGE_SIG', 'hex'),
          1,
          TRUE
      );" | psql talercheck

echo "SET search_path TO merchant;
      UPDATE merchant_contract_terms
      SET wired = TRUE
      WHERE order_serial = 1001
        AND NOT EXISTS (
            SELECT 1
            FROM merchant_deposit_confirmations
            WHERE wire_pending
              AND order_serial = 1001
        );" | psql talercheck

# Handle deposit confirmation
echo "SET search_path TO merchant;
      INSERT INTO merchant_deposit_confirmations (
          order_serial,
          deposit_timestamp,
          exchange_url,
          total_without_fee,
          wire_fee,
          signkey_serial,
          exchange_sig,
          account_serial,
          wire_pending
      ) VALUES (
          1001,
          EXTRACT(EPOCH FROM NOW()),
          'http://example.com/exchange',
          ROW(90, 0, 'USD')::taler_amount_currency,
          ROW(10, 0, 'USD')::taler_amount_currency,
          1,
          decode('$(openssl rand -hex 64)', 'hex'),
          1,
          FALSE
      );" | psql talercheck

echo "SET search_path TO merchant;
      UPDATE merchant_contract_terms
      SET wired = TRUE
      WHERE order_serial = 1001
        AND NOT EXISTS (
            SELECT 1
            FROM merchant_deposit_confirmations
            WHERE wire_pending
              AND order_serial = 1001
        );" | psql talercheck

# Add entries to merchant_deposits
echo "SET search_path TO merchant;
      INSERT INTO merchant_deposits (
          deposit_serial,
          coin_offset,
          deposit_confirmation_serial,
          coin_pub,
          coin_sig,
          amount_with_fee,
          deposit_fee,
          refund_fee
      ) VALUES (
          (SELECT COALESCE(MAX(deposit_serial), 0) + 1 FROM merchant_deposits),  -- deposit_serial
          0,  -- coin_offset
          1,  -- deposit_confirmation_serial (link to confirmation)
          decode('$COIN_PUB', 'hex'),  -- coin_pub
          decode('$(openssl rand -hex 64)', 'hex'),  -- coin_sig
          ROW(30, 0, 'USD')::taler_amount_currency,  -- amount_with_fee
          ROW(1, 0, 'USD')::taler_amount_currency,  -- deposit_fee
          ROW(0, 0, 'USD')::taler_amount_currency   -- refund_fee
      );" | psql talercheck

# Link deposits to wire transfers
echo "SET search_path TO merchant;
      INSERT INTO merchant_deposit_to_transfer (
          deposit_serial,
          coin_contribution_value,
          execution_time,
          signkey_serial,
          exchange_sig,
          wtid
      ) VALUES (
          (SELECT MAX(deposit_serial) FROM merchant_deposits),  -- deposit_serial
          ROW(10, 0, 'USD')::taler_amount_currency,  -- coin_contribution_value
          $EXECUTION_TIME,  -- execution_time
          1,  -- signkey_serial
          decode('$(openssl rand -hex 64)', 'hex'),  -- exchange_sig
          decode('$WTID', 'hex')  -- wtid
      );" | psql talercheck


# Debug the UPDATE condition
echo "SET search_path TO merchant;
      SELECT md.deposit_confirmation_serial, mdtt.wtid
      FROM merchant_deposits md
      LEFT JOIN merchant_deposit_to_transfer mdtt
        USING (deposit_serial)
      WHERE md.deposit_confirmation_serial=1
        AND mdtt.wtid IS NULL;" | psql talercheck

# Re-run the update logic
echo "SET search_path TO merchant;
      UPDATE merchant_deposit_confirmations
       SET wire_pending=FALSE
     WHERE deposit_confirmation_serial=1
       AND NOT EXISTS
       (SELECT 1
          FROM merchant_deposits md
          LEFT JOIN merchant_deposit_to_transfer mdtt
            USING (deposit_serial)
          WHERE md.deposit_confirmation_serial=1
            AND mdtt.wtid IS NULL);" | psql talercheck


echo "SET search_path TO merchant;
      SELECT merchant_do_insert_transfer_details(
          '$INSTANCE_ID',
          '$EXCHANGE_URL',
          '$PAYTO_URI',
          decode('$WTID', 'hex')::BYTEA,
          $EXECUTION_TIME::BIGINT,
          decode('$EXCHANGE_PUB', 'hex')::BYTEA,
          decode('$EXCHANGE_SIG', 'hex')::BYTEA,
          $TOTAL_AMOUNT,
          $WIRE_FEE,
          $COIN_VALUES,
          $DEPOSIT_FEES,
          $COIN_PUBS,
          $CONTRACT_TERMS
      );" | psql talercheck

# Echo all webhooks
echo "SET search_path TO merchant;
      SELECT * FROM merchant_pending_webhooks;" | psql talercheck

# Fetch and validate the number of pending webhooks
WEBHOOK_COUNT=$(echo "SET search_path TO merchant;
                       SELECT COUNT(*)
                       FROM merchant_pending_webhooks;" | psql talercheck -t -A | tr -d '[:space:]')

if [ "$WEBHOOK_COUNT" -ne 7 ]; then
  echo "ERROR: Expected 7 webhook entries, but received $WEBHOOK_COUNT."
  exit 1
else
  echo "SUCCESS: Received 7 webhook entries as expected."
fi
