USE [Database]

IF OBJECT_ID('[Procedures].[insert_or_update_barcode]', 'P') IS NOT NULL
  DROP PROCEDURE [Procedures].[insert_or_update_barcode];
GO
CREATE PROCEDURE [Procedures].[insert_or_update_barcode]
  @product_id                    AS INT,
  @barcode_attribute_id          AS INT,
  @barcode                       AS BIGINT = NULL,
  @record_id AS INT = NULL OUTPUT
AS
  BEGIN TRANSACTION;
    SET NOCOUNT ON;

	IF @barcode IS NOT NULL AND EXISTS(
      SELECT *
      FROM [Tables].[product_values]
      WHERE [attribute_id] = @barcode_attribute_id
          AND CAST([value] AS BIGINT) = @barcode
    )
    BEGIN;
	  IF @@TRANCOUNT > 0
	    ROLLBACK TRANSACTION;
      THROW 53000, 'The barcode is not unique', 1;
    END;

	CREATE TABLE [Tables].[#existing_hash_codes](
      [hash_code] NVARCHAR(13) 
    );
    INSERT INTO [#existing_hash_codes]([hash_code])
    SELECT [value]
    FROM [Tables].[product_attributes] AS [pa]
    JOIN [Tables].[product_values] AS [pv]
       ON [pv].[product_id] = [pa].[product_id]
          AND [pv].[attribute_id] = [pa].[attribute_id]
    WHERE [pa].[attribute_id] = @barcode_attribute_id
    
	-- begin creating barcode
    IF @barcode IS NULL
      EXECUTE [Procedures].[get_next_barcode] @next_barcode = @barcode OUTPUT;
    
    WHILE EXISTS(
      SELECT *
      FROM [#existing_hash_codes]
      WHERE CAST([hash_code] AS BIGINT) = @barcode
    )
	OR EXISTS(
	  SELECT *
      FROM [Tables].[product_values]
      WHERE [attribute_id] = @barcode_attribute_id
        AND CAST([value] AS BIGINT) = @barcode
	)
    BEGIN
      SET @barcode += 1;
    END
	-- end creating barcode

	IF EXISTS(
      SELECT *
      FROM [Tables].[product_values]
      WHERE [attribute_id] = @barcode_attribute_id
	    AND [product_id] = @product_id
	    AND [value] IS NOT NULL
    ) 
	BEGIN
	  UPDATE [Tables].[product_values]
      SET @record_id = [id],
	  [value] = [Functions].[to_barcode_ean_13](@barcode)
	  WHERE [product_id] = @product_id
	    AND [attribute_id] = @barcode_attribute_id;
	END
	ELSE BEGIN
	  INSERT INTO [Tables].[product_values]([product_id], [attribute_id], [value])
      VALUES(@product_id, @barcode_attribute_id, [Functions].[to_barcode_ean_13](@barcode));
      SET @record_id = SCOPE_IDENTITY();
	END
    
    COMMIT TRANSACTION;
GO
