--
-- 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/>
--


DROP FUNCTION IF EXISTS merchant_do_insert_product;
CREATE FUNCTION merchant_do_insert_product (
  IN in_instance_id TEXT,
  IN in_product_id TEXT,
  IN in_description TEXT,
  IN in_description_i18n JSONB,
  IN in_unit TEXT,
  IN in_image TEXT,
  IN in_taxes JSONB,
  IN in_price taler_amount_currency,
  IN ina_price_list taler_amount_currency[],
  IN in_total_stock INT8,
  IN in_total_stock_frac INT4,
  IN in_allow_fractional_quantity BOOL,
  IN in_fractional_precision_level INT4,
  IN in_address JSONB,
  IN in_next_restock INT8,
  IN in_minimum_age INT4,
  IN ina_categories INT8[],
  IN in_product_name TEXT,
  OUT out_no_instance BOOL,
  OUT out_conflict BOOL,
  OUT out_no_cat INT8)
LANGUAGE plpgsql
AS $$
DECLARE
  my_merchant_id INT8;
  my_product_serial INT8;
  i INT8;
  ini_cat INT8;
  my_price taler_amount_currency;
  my_price_array taler_amount_currency[];
BEGIN

-- Which instance are we using?
SELECT merchant_serial
  INTO my_merchant_id
  FROM merchant_instances
 WHERE merchant_id=in_instance_id;

IF NOT FOUND
THEN
  out_no_instance=TRUE;
  out_conflict=FALSE;
  out_no_cat=NULL;
  RETURN;
END IF;
out_no_instance=FALSE;

IF COALESCE (array_length(ina_price_list,1),0) = 0
THEN
  my_price_array := ARRAY[in_price]::taler_amount_currency[];
ELSE
  my_price_array := ina_price_list;
END IF;
my_price := my_price_array[1];

INSERT INTO merchant_inventory
 (merchant_serial
 ,product_id
 ,product_name
 ,description
 ,description_i18n
 ,unit
 ,image
 ,image_hash
 ,taxes
 ,price
 ,price_array
 ,total_stock
 ,total_stock_frac
 ,allow_fractional_quantity
 ,fractional_precision_level
 ,address
 ,next_restock
  ,minimum_age
) VALUES (
  my_merchant_id
 ,in_product_id
 ,in_product_name
 ,in_description
 ,in_description_i18n
 ,in_unit
 ,in_image
 ,CASE
    WHEN (in_image IS NULL) OR (in_image = '')
    THEN NULL
    ELSE encode(public.digest(convert_to(in_image, 'UTF8'),
                       'sha256'),
                'hex')
  END
 ,in_taxes
 ,my_price
 ,my_price_array
 ,in_total_stock
 ,in_total_stock_frac
 ,in_allow_fractional_quantity
 ,in_fractional_precision_level
 ,in_address
 ,in_next_restock
 ,in_minimum_age)
ON CONFLICT (merchant_serial, product_id) DO NOTHING
 RETURNING product_serial
 INTO my_product_serial;


IF NOT FOUND
THEN
  -- Check for idempotency
  SELECT product_serial
    INTO my_product_serial
    FROM merchant_inventory
  WHERE merchant_serial=my_merchant_id
    AND product_id=in_product_id
    AND product_name=in_product_name
    AND description=in_description
    AND description_i18n=in_description_i18n
    AND unit=in_unit
    AND image=in_image
    AND taxes=in_taxes
    AND price=my_price
    AND to_jsonb(COALESCE(price_array, ARRAY[]::taler_amount_currency[]))
        = to_jsonb(COALESCE(my_price_array, ARRAY[]::taler_amount_currency[]))
    AND total_stock=in_total_stock
    AND total_stock_frac=in_total_stock_frac
    AND allow_fractional_quantity=in_allow_fractional_quantity
    AND fractional_precision_level=in_fractional_precision_level
    AND address=in_address
    AND next_restock=in_next_restock
    AND minimum_age=in_minimum_age;
  IF NOT FOUND
  THEN
    out_conflict=TRUE;
    out_no_cat=NULL;
    RETURN;
  END IF;

  -- Check categories match as well
  FOR i IN 1..COALESCE(array_length(ina_categories,1),0)
  LOOP
    ini_cat=ina_categories[i];

    PERFORM
      FROM merchant_product_categories
      WHERE product_serial=my_product_serial
        AND category_serial=ini_cat;
    IF NOT FOUND
    THEN
      out_conflict=TRUE;
      out_no_cat=NULL;
      RETURN;
    END IF;
  END LOOP;

  -- Also check there are no additional categories
  -- in either set.
  SELECT COUNT(*)
    INTO i
    FROM merchant_product_categories
    WHERE product_serial=my_product_serial;
  IF i != array_length(ina_categories,1)
  THEN
    out_conflict=TRUE;
    out_no_cat=NULL;
    RETURN;
  END IF;

  -- Is idempotent!
  out_conflict=FALSE;
  out_no_cat=NULL;
  RETURN;
END IF;
out_conflict=FALSE;


-- Add categories
FOR i IN 1..COALESCE(array_length(ina_categories,1),0)
LOOP
  ini_cat=ina_categories[i];

  INSERT INTO merchant_product_categories
   (product_serial
   ,category_serial)
  VALUES
   (my_product_serial
   ,ini_cat)
  ON CONFLICT DO NOTHING;

  IF NOT FOUND
  THEN
    out_no_cat=i;
    RETURN;
  END IF;
END LOOP;

-- Success!
out_no_cat=NULL;
END $$;
