--
-- 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_update_product;
CREATE FUNCTION merchant_do_update_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_total_lost INT8,
  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_no_product BOOL,
  OUT out_lost_reduced BOOL,
  OUT out_sold_reduced BOOL,
  OUT out_stocked_reduced BOOL,
  OUT out_no_cat INT8)
LANGUAGE plpgsql
AS $$
DECLARE
  my_merchant_id INT8;
  my_product_serial INT8;
  i INT8;
  ini_cat INT8;
  rec RECORD;
  my_price taler_amount_currency;
  my_price_array taler_amount_currency[];
BEGIN

out_no_instance=FALSE;
out_no_product=FALSE;
out_lost_reduced=FALSE;
out_sold_reduced=FALSE; -- We currently don't allow updating 'sold', hence always FALSE
out_stocked_reduced=FALSE;
out_no_cat=NULL;

-- 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;
  RETURN;
END IF;

-- Check existing entry satisfies constraints
SELECT total_stock
      ,total_stock_frac
      ,total_lost
      ,allow_fractional_quantity
      ,product_serial
  INTO rec
  FROM merchant_inventory
 WHERE merchant_serial=my_merchant_id
   AND product_id=in_product_id;

IF NOT FOUND
THEN
  out_no_product=TRUE;
  RETURN;
END IF;

my_product_serial = rec.product_serial;

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];

IF rec.total_stock > in_total_stock
THEN
  out_stocked_reduced=TRUE;
  RETURN;
END IF;

IF rec.total_lost > in_total_lost
THEN
  out_lost_reduced=TRUE;
  RETURN;
END IF;
IF rec.allow_fractional_quantity
   AND (NOT in_allow_fractional_quantity)
THEN
  DELETE
    FROM merchant_inventory_locks
   WHERE product_serial = my_product_serial
     AND total_locked_frac <> 0;
END IF;

-- Remove old categories
DELETE FROM merchant_product_categories
  WHERE product_serial=my_product_serial;

-- Add new 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;

UPDATE merchant_inventory SET
   description=in_description
  ,description_i18n=in_description_i18n
  ,product_name=in_product_name
  ,unit=in_unit
  ,image=in_image
  ,image_hash=CASE
               WHEN (in_image IS NULL) OR (in_image = '')
               THEN NULL
               ELSE encode(public.digest(convert_to(in_image, 'UTF8'),
                                  'sha256'),
                           'hex')
             END
  ,taxes=in_taxes
  ,price=my_price
  ,price_array=my_price_array
  ,total_stock=in_total_stock
  ,total_stock_frac=in_total_stock_frac
  ,allow_fractional_quantity=in_allow_fractional_quantity
  ,fractional_precision_level=in_fractional_precision_level
  ,total_lost=in_total_lost
  ,address=in_address
  ,next_restock=in_next_restock
  ,minimum_age=in_minimum_age
 WHERE merchant_serial=my_merchant_id
   AND product_serial=my_product_serial; -- could also match on product_id

ASSERT FOUND,'SELECTED it earlier, should UPDATE it now';

-- Success!
END $$;
