
CREATE OR REPLACE PROCEDURE tcg.public.USP_TCG_MTG_Inventory_Save (
      a_comment TEXT
    , a_guid UUID
    , a_user_id INT
	, OUT o_success BOOLEAN
)
LANGUAGE plpgsql
AS $$
DECLARE
	v_bad_data_error_type_id INT;
	v_change_set_id INT;
	-- v_error_message TEXT;
	v_time_start TIMESTAMP;
	v_warning_error_type_id INT;
BEGIN
	v_bad_data_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'BAD_DATA' LIMIT 1);
	v_warning_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'WARNING' LIMIT 1);
	v_time_start := CURRENT_TIMESTAMP;
	
	DROP TABLE IF EXISTS Temp_MTG_Inventory_Save_Inventory;
	DROP TABLE IF EXISTS Temp_MTG_Inventory_Save_Card;
	DROP TABLE IF EXISTS Temp_MTG_Inventory_Save_Error;

	CREATE TEMP TABLE Temp_MTG_Inventory_Save_Inventory (
		  temp_id INT NOT NULL
	    , inventory_id INT
	    , card_id INT
	    , finish_id INT NOT NULL
	    , condition_id INT NOT NULL
	    , sleeve_colour_name TEXT
	    , location_name TEXT
	    , acquired_from TEXT
	    , acquired_on TIMESTAMP
	    , cost_gbp DECIMAL(6, 2) NOT NULL
	    , sale_price_gbp DECIMAL(6, 2)
	    , is_sold BOOLEAN NOT NULL DEFAULT FALSE
	    , is_destroyed BOOLEAN NOT NULL DEFAULT FALSE
	    , notes TEXT
	    , alterations_customisations TEXT
	    , grading_company_name TEXT
	    , grading_score TEXT
	    , subgrades TEXT
	    , misprint_errors TEXT
	    , miscut_errors TEXT
	    , playability TEXT
	    , owner_user_id INT NOT NULL
	    , ownership_status_name TEXT
	    , trading_status_name TEXT
	    , loaned_to_user_id INT
	    , loan_start_on TIMESTAMP
	    , loan_end_on TIMESTAMP
	    , provenance TEXT
	    , signed_by_names TEXT
	    , signature_condition_name TEXT
	    , token_rear_side_card_id INT
	    , display_order INT NOT NULL
	    , active BOOLEAN NOT NULL
		, created_on TIMESTAMP
		, created_by_user_id INT NOT NULL
		, updated_last_on TIMESTAMP
		, updated_last_by_user_id INT NOT NULL
	    , change_set_id INT NOT NULL
	    , set_code TEXT
	    , collector_number TEXT
	    , name TEXT
	    , is_token BOOLEAN
	    , token_rear_side_name TEXT
	    , token_rear_side_set_code TEXT
	    , token_rear_side_collector_number TEXT

		, is_new BOOLEAN
		, error_name TEXT
		, has_valid_main_card BOOLEAN
		, has_matching_main_name BOOLEAN
		, has_valid_rear_card BOOLEAN
		, has_matching_rear_name BOOLEAN
		, is_unique BOOLEAN
		, missing_mandatory_fields TEXT
	);

	CREATE TEMP TABLE Temp_MTG_Inventory_Save_Card (
		  card_id INT NOT NULL
	    , all_parts TEXT
	    , arena_id INTEGER
	    , artist TEXT
	    , artist_ids TEXT
	    , booster BOOLEAN
	    , border_color TEXT
	    , card_back_id TEXT
	    , card_faces TEXT
	    , cardmarket_id INTEGER
	    , cmc DECIMAL(8, 1)
	    , collector_number TEXT
	    , color_identity TEXT
	    , colors TEXT
	    , content_warning BOOLEAN
	    , digital BOOLEAN
	    , edhrec_rank INTEGER
	    , finishes TEXT
	    , flavor_name TEXT
	    , flavor_text TEXT
	    , foil BOOLEAN
	    , frame TEXT
	    , full_art BOOLEAN
	    , game_changer BOOLEAN
	    , games TEXT
	    , hand_modifier TEXT
	    , highres_image BOOLEAN
	    , id TEXT
	    , image_status TEXT
	    , image_uri_art_crop TEXT
	    , image_uri_border_crop TEXT
	    , image_uri_large TEXT
	    , image_uri_normal TEXT
	    , image_uri_png TEXT
	    , image_uri_small TEXT
	    , keywords TEXT
	    , lang TEXT
	    , layout TEXT
	    , legal_alchemy BOOLEAN
	    , legal_brawl BOOLEAN
	    , legal_commander BOOLEAN
	    , legal_duel BOOLEAN
	    , legal_future BOOLEAN
	    , legal_gladiator BOOLEAN
	    , legal_historic BOOLEAN
	    , legal_legacy BOOLEAN
	    , legal_modern BOOLEAN
	    , legal_oathbreaker BOOLEAN
	    , legal_oldschool BOOLEAN
	    , legal_pauper BOOLEAN
	    , legal_paupercommander BOOLEAN
	    , legal_penny BOOLEAN
	    , legal_pioneer BOOLEAN
	    , legal_predh BOOLEAN
	    , legal_premodern BOOLEAN
	    , legal_standard BOOLEAN
	    , legal_standardbrawl BOOLEAN
	    , legal_timeless BOOLEAN
	    , legal_vintage BOOLEAN
	    , life_modifier TEXT
	    , loyalty TEXT
	    , mana_cost TEXT
	    , mtgo_id INTEGER
	    , multiverse_ids TEXT
	    , name TEXT NOT NULL
	    , nonfoil BOOLEAN
	    , oracle_id TEXT
	    , oracle_text TEXT
	    , oversized BOOLEAN
	    , penny_rank INTEGER
	    , power TEXT
	    , preview_date DATE
	    , preview_source TEXT
	    , preview_source_uri TEXT
	    , price_eur DECIMAL(10, 3)
	    , price_eur_foil DECIMAL(10, 3)
	    , price_tix DECIMAL(10, 3)
	    , price_usd DECIMAL(10, 3)
	    , price_usd_etched DECIMAL(10, 3)
	    , price_usd_foil DECIMAL(10, 3)
	    , printed_name TEXT
	    , printed_text TEXT
	    , printed_type_line TEXT
	    , prints_search_uri TEXT
	    , produced_mana TEXT
	    , promo BOOLEAN
	    , purchase_cardhoarder TEXT
	    , purchase_cardmarket TEXT
	    , purchase_tcgplayer TEXT
	    , rarity TEXT
	    , released_at DATE
	    , reprint BOOLEAN
	    , reserved BOOLEAN
	    , rulings_uri TEXT
	    , scryfall_set_uri TEXT
	    , scryfall_uri TEXT
	    , security_stamp TEXT
	    , set TEXT
	    , set_id TEXT
	    , set_name TEXT
	    , set_search_uri TEXT
	    , set_type TEXT
	    , set_uri TEXT
	    , story_spotlight BOOLEAN
	    , tcgplayer_id INTEGER
	    , textless BOOLEAN
	    , toughness TEXT
	    , type_line TEXT
	    , uri TEXT
	    , uri_edhrec TEXT
	    , uri_gatherer TEXT
	    , uri_tcgplayer_infinite_articles TEXT
	    , uri_tcgplayer_infinite_decks TEXT
	    , variation BOOLEAN
	    , active BOOLEAN
	);

	CREATE TEMP TABLE Temp_MTG_Inventory_Save_Error (
		  temp_id INT GENERATED ALWAYS AS IDENTITY
		, error_type_id INT
		, message TEXT
	);
	
	WITH Inventory_Face AS (
		SELECT
			  INVENTORY_T.temp_id
			, CASE
		        WHEN POSITION('//' in INVENTORY_T.name) > 0
		        THEN LEFT(INVENTORY_T.name, POSITION('//' in INVENTORY_T.name) - 2)
		        ELSE INVENTORY_T.name
		    END AS front_name
		    , CASE
			    WHEN TRIM(COALESCE(INVENTORY_T.token_rear_side_name, '')) <> ''
			    THEN INVENTORY_T.token_rear_side_name
		        WHEN POSITION('//' in INVENTORY_T.name) > 0
		        THEN SUBSTRING(INVENTORY_T.name from POSITION('//' in INVENTORY_T.name) + 3)
		        ELSE NULL
		    END AS rear_name
			, CASE
		        WHEN POSITION('//' in INVENTORY_T.set_code) > 0
		        THEN LOWER(LEFT(INVENTORY_T.set_code, POSITION('//' in INVENTORY_T.set_code) - 2))
		        ELSE LOWER(INVENTORY_T.set_code)
		    END AS front_set_code
		    , CASE
			    WHEN TRIM(COALESCE(INVENTORY_T.token_rear_side_set_code, '')) <> ''
			    THEN LOWER(INVENTORY_T.token_rear_side_set_code)
		        WHEN POSITION('//' in INVENTORY_T.set_code) > 0
		        THEN LOWER(SUBSTRING(INVENTORY_T.set_code from POSITION('//' in INVENTORY_T.set_code) + 3))
		        ELSE LOWER(INVENTORY_T.set_code)
		    END AS rear_set_code
			, CASE
		        WHEN INVENTORY_T.collector_number ~ '^-?[0-9]+\.?[0-9]*$'
		        THEN INVENTORY_T.collector_number::NUMERIC::INTEGER
		        WHEN POSITION('//' in INVENTORY_T.collector_number) > 0
		        THEN LEFT(INVENTORY_T.collector_number, POSITION('//' in INVENTORY_T.collector_number) - 2)::NUMERIC::INTEGER
		        ELSE INVENTORY_T.collector_number::NUMERIC::INTEGER
		    END AS front_collector_number
		    , CASE
			    /*
		        WHEN INVENTORY_T.collector_number ~ '^-?[0-9]+\.?[0-9]*$'
		        THEN INVENTORY_T.collector_number::NUMERIC::INTEGER
		        */
			    WHEN TRIM(COALESCE(INVENTORY_T.token_rear_side_collector_number, '')) <> ''
			    THEN INVENTORY_T.token_rear_side_collector_number::NUMERIC::INTEGER
		        WHEN POSITION('//' in INVENTORY_T.collector_number) > 0
		        THEN SUBSTRING(INVENTORY_T.collector_number from POSITION('//' in INVENTORY_T.collector_number) + 3)::NUMERIC::INTEGER
		        ELSE NULL::INTEGER
		    END AS rear_collector_number
		FROM tcg.public.TCG_MTG_Inventory_Temp INVENTORY_T
	)
	INSERT INTO Temp_MTG_Inventory_Save_Inventory (
		  temp_id
	    , inventory_id
	    , card_id
	    , finish_id
	    , condition_id
	    , sleeve_colour_name
	    , location_name
	    , acquired_from
	    , acquired_on
	    , cost_gbp
	    , sale_price_gbp
	    , is_sold
	    , is_destroyed
	    , notes
	    , alterations_customisations
	    , grading_company_name
	    , grading_score
	    , subgrades
	    , misprint_errors
	    , miscut_errors
	    , playability
	    , owner_user_id
	    , ownership_status_name
	    , trading_status_name
	    , loaned_to_user_id
	    , loan_start_on
	    , loan_end_on
	    , provenance
	    , signed_by_names
	    , signature_condition_name
	    , token_rear_side_card_id
	    , display_order
	    , active
		, created_on
		, created_by_user_id
		, updated_last_on
		, updated_last_by_user_id
	    , change_set_id
	    , set_code
	    , collector_number
	    , name
	    , is_token
	    , token_rear_side_name
	    , token_rear_side_set_code
	    , token_rear_side_collector_number

		, is_new
		, error_name
		, has_valid_main_card
		, has_matching_main_name
		, has_valid_rear_card
		, has_matching_rear_name
	)
	SELECT
		  INVENTORY_T.temp_id
	    , INVENTORY_T.inventory_id
	    , MAIN_CARD.card_id -- card_id
	    , INVENTORY_T.finish_id
	    , INVENTORY_T.condition_id
	    , INVENTORY_T.sleeve_colour_name
	    , INVENTORY_T.location_name
	    , INVENTORY_T.acquired_from
	    , INVENTORY_T.acquired_on
	    , INVENTORY_T.cost_gbp
	    , INVENTORY_T.sale_price_gbp
	    , INVENTORY_T.is_sold
	    , INVENTORY_T.is_destroyed
	    , INVENTORY_T.notes
	    , INVENTORY_T.alterations_customisations
	    , INVENTORY_T.grading_company_name
	    , INVENTORY_T.grading_score
	    , INVENTORY_T.subgrades
	    , INVENTORY_T.misprint_errors
	    , INVENTORY_T.miscut_errors
	    , INVENTORY_T.playability
	    , INVENTORY_T.owner_user_id
	    , INVENTORY_T.ownership_status_name
	    , INVENTORY_T.trading_status_name
	    , INVENTORY_T.loaned_to_user_id
	    , INVENTORY_T.loan_start_on
	    , INVENTORY_T.loan_end_on
	    , INVENTORY_T.provenance
	    , INVENTORY_T.signed_by_names
	    , INVENTORY_T.signature_condition_name
	    , REAR_CARD.card_id -- token_rear_side_card_id
	    , INVENTORY_T.display_order
	    , COALESCE(INVENTORY_T.active, TRUE) AS active
		, v_time_start -- created_on
		, a_user_id -- created_by_user_id
		, v_time_start -- updated_last_on
		, a_user_id -- updated_last_by_user_id
	    , INVENTORY_T.change_set_id
	    , INVENTORY_FACE.front_set_code -- set_code
	    , INVENTORY_FACE.front_collector_number -- collector_number
	    , INVENTORY_FACE.front_name -- name
	    , INVENTORY_T.is_token
	    , INVENTORY_FACE.rear_name -- token_rear_side_name
	    , INVENTORY_FACE.rear_set_code -- token_rear_side_set_code
	    , INVENTORY_FACE.rear_collector_number -- token_rear_side_collector_number

		, CASE WHEN INVENTORY.inventory_id IS NULL THEN TRUE ELSE FALSE END AS is_new
		, CONCAT(
			  'Inventory { id: '
			, CAST(INVENTORY_T.inventory_id AS VARCHAR)
			, ', temp id: '
			, CAST(INVENTORY_T.temp_id AS VARCHAR)
			, ', display order: '
			, CAST(INVENTORY_T.display_order AS VARCHAR)
			, ', collector #: '
			, CAST(INVENTORY_FACE.front_collector_number AS VARCHAR)
			, ', set: '
			, INVENTORY_FACE.front_set_code
			, ', name: '
			, INVENTORY_FACE.front_name
			, ', rear collector #: '
			, CAST(INVENTORY_FACE.rear_collector_number AS VARCHAR)
			, ', rear set: '
			, INVENTORY_FACE.rear_set_code
			, ', rear name: '
			, INVENTORY_FACE.rear_name
			, ' }'
		) -- error_name
		, CASE WHEN MAIN_CARD.card_id IS NOT NULL THEN TRUE ELSE FALSE END AS has_valid_main_card
		, CASE WHEN MAIN_CARD.name = INVENTORY_T.name THEN TRUE ELSE FALSE END AS has_matching_main_name
		, CASE WHEN REAR_CARD.card_id IS NOT NULL THEN TRUE ELSE FALSE END AS has_valid_rear_card
		, CASE WHEN REAR_CARD.name = INVENTORY_T.name THEN TRUE ELSE FALSE END AS has_matching_rear_name
	FROM tcg.public.TCG_MTG_Inventory_Temp INVENTORY_T
	INNER JOIN Inventory_Face INVENTORY_FACE ON INVENTORY_T.temp_id = INVENTORY_FACE.temp_id
	LEFT JOIN tcg.public.TCG_MTG_Card MAIN_CARD
	    ON  (
	    		(
		    		INVENTORY_T.is_token = FALSE
	        	AND INVENTORY_FACE.front_name <> 'Art Card'
				AND INVENTORY_FACE.front_set_code = MAIN_CARD.set
			)
	        OR  (
	        		INVENTORY_T.is_token = TRUE
	        	AND MAIN_CARD.set_type = 'token'
	        	AND 't' || INVENTORY_FACE.front_set_code = MAIN_CARD.set
	        )
	        OR  (
	        		INVENTORY_FACE.front_name = 'Art Card'
	        	AND 'a' || INVENTORY_FACE.front_set_code = MAIN_CARD.set
	        )
	    )
	    AND INVENTORY_FACE.front_collector_number = CASE 
	        WHEN MAIN_CARD.collector_number ~ '^-?[0-9]+\.?[0-9]*$' 
	        THEN MAIN_CARD.collector_number::NUMERIC::INTEGER 
	        ELSE NULL 
	    END
	LEFT JOIN tcg.public.TCG_MTG_Card REAR_CARD
	    ON  (
	    		(
		    		INVENTORY_T.is_token = FALSE
	        	AND INVENTORY_FACE.rear_name = REAR_CARD.name
				AND INVENTORY_FACE.rear_set_code = REAR_CARD.set
			)
	        OR  (
	        		INVENTORY_T.is_token = TRUE
	        	AND REAR_CARD.set_type = 'token'
	        	AND INVENTORY_FACE.rear_name = REAR_CARD.name
	        	AND 't' || INVENTORY_FACE.rear_set_code = REAR_CARD.set
	        )
	    )
	    AND INVENTORY_FACE.rear_collector_number = CASE 
	        WHEN REAR_CARD.collector_number ~ '^-?[0-9]+\.?[0-9]*$' 
	        THEN REAR_CARD.collector_number::NUMERIC::INTEGER 
	        ELSE NULL 
	    END
	LEFT JOIN tcg.public.TCG_MTG_Inventory INVENTORY ON INVENTORY_T.inventory_id = INVENTORY.inventory_id
	WHERE INVENTORY_T.guid = a_guid
	;
	
	INSERT INTO Temp_MTG_Inventory_Save_Card (
		  card_id
	    , all_parts
	    , arena_id
	    , artist
	    , artist_ids
	    , booster
	    , border_color
	    , card_back_id
	    , card_faces
	    , cardmarket_id
	    , cmc
	    , collector_number
	    , color_identity
	    , colors
	    , content_warning
	    , digital
	    , edhrec_rank
	    , finishes
	    , flavor_name
	    , flavor_text
	    , foil
	    , frame
	    , full_art
	    , game_changer
	    , games
	    , hand_modifier
	    , highres_image
	    , id
	    , image_status
	    , image_uri_art_crop
	    , image_uri_border_crop
	    , image_uri_large
	    , image_uri_normal
	    , image_uri_png
	    , image_uri_small
	    , keywords
	    , lang
	    , layout
	    , legal_alchemy
	    , legal_brawl
	    , legal_commander
	    , legal_duel
	    , legal_future
	    , legal_gladiator
	    , legal_historic
	    , legal_legacy
	    , legal_modern
	    , legal_oathbreaker
	    , legal_oldschool
	    , legal_pauper
	    , legal_paupercommander
	    , legal_penny
	    , legal_pioneer
	    , legal_predh
	    , legal_premodern
	    , legal_standard
	    , legal_standardbrawl
	    , legal_timeless
	    , legal_vintage
	    , life_modifier
	    , loyalty
	    , mana_cost
	    , mtgo_id
	    , multiverse_ids
	    , name
	    , nonfoil
	    , oracle_id
	    , oracle_text
	    , oversized
	    , penny_rank
	    , power
	    , preview_date
	    , preview_source
	    , preview_source_uri
	    , price_eur
	    , price_eur_foil
	    , price_tix
	    , price_usd
	    , price_usd_etched
	    , price_usd_foil
	    , printed_name
	    , printed_text
	    , printed_type_line
	    , prints_search_uri
	    , produced_mana
	    , promo
	    , purchase_cardhoarder
	    , purchase_cardmarket
	    , purchase_tcgplayer
	    , rarity
	    , released_at
	    , reprint
	    , reserved
	    , rulings_uri
	    , scryfall_set_uri
	    , scryfall_uri
	    , security_stamp
	    , set
	    , set_id
	    , set_name
	    , set_search_uri
	    , set_type
	    , set_uri
	    , story_spotlight
	    , tcgplayer_id
	    , textless
	    , toughness
	    , type_line
	    , uri
	    , uri_edhrec
	    , uri_gatherer
	    , uri_tcgplayer_infinite_articles
	    , uri_tcgplayer_infinite_decks
	    , variation
	    , active
	)
	SELECT
		  CARD.card_id
	    , CARD.all_parts
	    , CARD.arena_id
	    , CARD.artist
	    , CARD.artist_ids
	    , CARD.booster
	    , CARD.border_color
	    , CARD.card_back_id
	    , CARD.card_faces
	    , CARD.cardmarket_id
	    , CARD.cmc
	    , CARD.collector_number
	    , CARD.color_identity
	    , CARD.colors
	    , CARD.content_warning
	    , CARD.digital
	    , CARD.edhrec_rank
	    , CARD.finishes
	    , CARD.flavor_name
	    , CARD.flavor_text
	    , CARD.foil
	    , CARD.frame
	    , CARD.full_art
	    , CARD.game_changer
	    , CARD.games
	    , CARD.hand_modifier
	    , CARD.highres_image
	    , CARD.id
	    , CARD.image_status
	    , CARD.image_uri_art_crop
	    , CARD.image_uri_border_crop
	    , CARD.image_uri_large
	    , CARD.image_uri_normal
	    , CARD.image_uri_png
	    , CARD.image_uri_small
	    , CARD.keywords
	    , CARD.lang
	    , CARD.layout
	    , CARD.legal_alchemy
	    , CARD.legal_brawl
	    , CARD.legal_commander
	    , CARD.legal_duel
	    , CARD.legal_future
	    , CARD.legal_gladiator
	    , CARD.legal_historic
	    , CARD.legal_legacy
	    , CARD.legal_modern
	    , CARD.legal_oathbreaker
	    , CARD.legal_oldschool
	    , CARD.legal_pauper
	    , CARD.legal_paupercommander
	    , CARD.legal_penny
	    , CARD.legal_pioneer
	    , CARD.legal_predh
	    , CARD.legal_premodern
	    , CARD.legal_standard
	    , CARD.legal_standardbrawl
	    , CARD.legal_timeless
	    , CARD.legal_vintage
	    , CARD.life_modifier
	    , CARD.loyalty
	    , CARD.mana_cost
	    , CARD.mtgo_id
	    , CARD.multiverse_ids
	    , CARD.name
	    , CARD.nonfoil
	    , CARD.oracle_id
	    , CARD.oracle_text
	    , CARD.oversized
	    , CARD.penny_rank
	    , CARD.power
	    , CARD.preview_date
	    , CARD.preview_source
	    , CARD.preview_source_uri
	    , CARD.price_eur
	    , CARD.price_eur_foil
	    , CARD.price_tix
	    , CARD.price_usd
	    , CARD.price_usd_etched
	    , CARD.price_usd_foil
	    , CARD.printed_name
	    , CARD.printed_text
	    , CARD.printed_type_line
	    , CARD.prints_search_uri
	    , CARD.produced_mana
	    , CARD.promo
	    , CARD.purchase_cardhoarder
	    , CARD.purchase_cardmarket
	    , CARD.purchase_tcgplayer
	    , CARD.rarity
	    , CARD.released_at
	    , CARD.reprint
	    , CARD.reserved
	    , CARD.rulings_uri
	    , CARD.scryfall_set_uri
	    , CARD.scryfall_uri
	    , CARD.security_stamp
	    , CARD.set
	    , CARD.set_id
	    , CARD.set_name
	    , CARD.set_search_uri
	    , CARD.set_type
	    , CARD.set_uri
	    , CARD.story_spotlight
	    , CARD.tcgplayer_id
	    , CARD.textless
	    , CARD.toughness
	    , CARD.type_line
	    , CARD.uri
	    , CARD.uri_edhrec
	    , CARD.uri_gatherer
	    , CARD.uri_tcgplayer_infinite_articles
	    , CARD.uri_tcgplayer_infinite_decks
	    , CARD.variation
	    , CARD.active
	FROM tcg.public.TCG_MTG_Card CARD
	INNER JOIN Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		ON  CARD.card_id = T_INVENTORY.card_id
		OR  CARD.card_id = T_INVENTORY.token_rear_side_card_id
	;

	-- Missing fields
	WITH
		  Inventory_Missing_Field AS (
			/* Card ID completed above
			SELECT
				T_INVENTORY.temp_id
				, 'card_id' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.card_id IS NULL
			*/
			SELECT
				T_INVENTORY.temp_id
				, 'finish_id' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.finish_id IS NULL
			UNION
			SELECT
				T_INVENTORY.temp_id
				, 'condition_id' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.condition_id IS NULL
			UNION
			SELECT
				T_INVENTORY.temp_id
				, 'cost_gbp' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.cost_gbp IS NULL
			UNION
			SELECT
				T_INVENTORY.temp_id
				, 'owner_user_id' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.owner_user_id IS NULL
			UNION
			SELECT
				T_INVENTORY.temp_id
				, 'display_order' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.display_order IS NULL
			UNION
			SELECT
				T_INVENTORY.temp_id
				, 'front_name' AS field
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			WHERE T_INVENTORY.name IS NULL
		)
	/*
	UPDATE Temp_MTG_Inventory_Save_Inventory T_INVENTORY
	SET missing_mandatory_fields = INVENTORY_MISSING_FIELD.missing_field_names
	FROM Inventory_Missing_Field INVENTORY_MISSING_FIELD
	WHERE INVENTORY_MISSING_FIELD.temp_id = T_INVENTORY.temp_id
	;
	IF EXISTS (SELECT * FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY WHERE T_INVENTORY.missing_mandatory_fields IS NOT NULL LIMIT 1) THEN
	*/
	INSERT INTO Temp_MTG_Inventory_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Missing mandatory field: '
			, INVENTORY_MISSING_FIELD.field
			, ' on '
			, T_INVENTORY.error_name
			, '.'
		) -- message
	FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
	INNER JOIN Inventory_Missing_Field INVENTORY_MISSING_FIELD ON T_INVENTORY.temp_id = INVENTORY_MISSING_FIELD.temp_id
	WHERE T_INVENTORY.missing_mandatory_fields IS NOT NULL
-- 	END IF;
	;

	-- Missing front card
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE T_INVENTORY.has_valid_main_card = FALSE
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Inventory_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Front card not found on '
				, T_INVENTORY.error_name
			) -- message
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE T_INVENTORY.has_valid_main_card = FALSE
		;
	END IF;

	-- Mismatch front name
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE
				T_INVENTORY.has_valid_main_card = TRUE
			AND T_INVENTORY.has_matching_main_name = FALSE
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Inventory_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Front card name mismatch on '
				, T_INVENTORY.error_name
			) -- message
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		INNER JOIN Temp_MTG_Inventory_Save_Card T_CARD ON T_INVENTORY.card_id = T_CARD.card_id
		WHERE
				T_INVENTORY.has_valid_main_card = TRUE
			AND T_INVENTORY.has_matching_main_name = FALSE
		;
	END IF;

	-- Missing rear card
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE
				T_INVENTORY.has_valid_rear_card = FALSE
			AND (
					T_INVENTORY.token_rear_side_collector_number IS NOT NULL
				OR	T_INVENTORY.token_rear_side_set_code IS NOT NULL
				OR	T_INVENTORY.token_rear_side_name IS NOT NULL
			)
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Inventory_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Front card not found on '
				, T_INVENTORY.error_name
			) -- message
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE
				T_INVENTORY.has_valid_rear_card = FALSE
			AND (
					T_INVENTORY.token_rear_side_collector_number IS NOT NULL
				OR	T_INVENTORY.token_rear_side_set_code IS NOT NULL
				OR	T_INVENTORY.token_rear_side_name IS NOT NULL
			)
		;
	END IF;

	-- Mismatch rear name
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE
				T_INVENTORY.has_valid_rear_card = TRUE
			AND (
					T_INVENTORY.token_rear_side_collector_number IS NOT NULL
				OR	T_INVENTORY.token_rear_side_set_code IS NOT NULL
				OR	T_INVENTORY.token_rear_side_name IS NOT NULL
			)
			AND T_INVENTORY.has_matching_rear_name = FALSE
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Inventory_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Front card name mismatch on '
				, T_INVENTORY.error_name
			) -- message
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		INNER JOIN Temp_MTG_Inventory_Save_Card T_CARD ON T_INVENTORY.card_id = T_CARD.card_id
		WHERE
				T_INVENTORY.has_valid_rear_card = TRUE
			AND (
					T_INVENTORY.token_rear_side_collector_number IS NOT NULL
				OR	T_INVENTORY.token_rear_side_set_code IS NOT NULL
				OR	T_INVENTORY.token_rear_side_name IS NOT NULL
			)
			AND T_INVENTORY.has_matching_rear_name = FALSE
		;
	END IF;

	-- Not unique card alignment
	WITH 
		  Non_Unique_Card_Face AS (
			SELECT
				  T_INVENTORY.temp_id
				, FALSE AS is_unique
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			GROUP BY T_INVENTORY.temp_id
			HAVING COUNT(*) > 1
		)
		, Inventory_Card AS (
			SELECT
				  T_INVENTORY.temp_id
				, CASE WHEN CARD.temp_id IS NULL THEN TRUE ELSE FALSE END AS is_unique
			FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
			LEFT JOIN Non_Unique_Card_Face CARD ON T_INVENTORY.temp_id = CARD.temp_id
		)
	UPDATE Temp_MTG_Inventory_Save_Inventory T_INVENTORY
	SET is_unique = CARD.is_unique
	FROM Inventory_Card CARD
	WHERE T_INVENTORY.temp_id = CARD.temp_id
	;
	
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE T_INVENTORY.is_unique = FALSE
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Inventory_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Front card not found on '
				, T_INVENTORY.error_name
			) -- message
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE T_INVENTORY.is_unique = FALSE
		;
	END IF;

	-- Nothing to save
	IF NOT EXISTS (SELECT * FROM Temp_MTG_Inventory_Save_Inventory LIMIT 1) THEN
		INSERT INTO Temp_MTG_Inventory_Save_Error (
			  error_type_id
			, message
		)
		VALUES (
			  v_warning_error_type_id
			, 'Nothing to save.'
		);
	END IF;

	-- Outputs
	-- Change Set
	INSERT INTO tcg.public.TCG_Change_Set (
		  comment
		, updated_last_by_user_id
	)
	VALUES (
		  a_comment
		, a_user_id
	)
	RETURNING change_set_id INTO v_change_set_id
	;
	
	IF NOT EXISTS (SELECT * FROM Temp_MTG_Inventory_Save_Error LIMIT 1) THEN
		
		-- Inventory
		INSERT INTO tcg.public.TCG_MTG_Inventory (
			  card_id
		    , finish_id
		    , condition_id
		    , sleeve_colour_name
		    , location_name
		    , acquired_from
		    , acquired_on
		    , cost_gbp
		    , sale_price_gbp
		    , is_sold
		    , is_destroyed
		    , notes
		    , alterations_customisations
		    , grading_company_name
		    , grading_score
		    , subgrades
		    , misprint_errors
		    , miscut_errors
		    , playability
		    , owner_user_id
		    , ownership_status_name
		    , trading_status_name
		    , loaned_to_user_id
		    , loan_start_on
		    , loan_end_on
		    , provenance
		    , signed_by_names
		    , signature_condition_name
		    , token_rear_side_card_id
		    , display_order
			, front_name
			, rear_name
		    , active
			, created_on
			, created_by_user_id
			, updated_last_on
			, updated_last_by_user_id
		    , change_set_id
		)
		SELECT
			  T_INVENTORY.card_id
		    , T_INVENTORY.finish_id
		    , T_INVENTORY.condition_id
		    , T_INVENTORY.sleeve_colour_name
		    , T_INVENTORY.location_name
		    , T_INVENTORY.acquired_from
		    , T_INVENTORY.acquired_on
		    , T_INVENTORY.cost_gbp
		    , T_INVENTORY.sale_price_gbp
		    , T_INVENTORY.is_sold
		    , T_INVENTORY.is_destroyed
		    , T_INVENTORY.notes
		    , T_INVENTORY.alterations_customisations
		    , T_INVENTORY.grading_company_name
		    , T_INVENTORY.grading_score
		    , T_INVENTORY.subgrades
		    , T_INVENTORY.misprint_errors
		    , T_INVENTORY.miscut_errors
		    , T_INVENTORY.playability
		    , T_INVENTORY.owner_user_id
		    , T_INVENTORY.ownership_status_name
		    , T_INVENTORY.trading_status_name
		    , T_INVENTORY.loaned_to_user_id
		    , T_INVENTORY.loan_start_on
		    , T_INVENTORY.loan_end_on
		    , T_INVENTORY.provenance
		    , T_INVENTORY.signed_by_names
		    , T_INVENTORY.signature_condition_name
		    , T_INVENTORY.token_rear_side_card_id
		    , T_INVENTORY.display_order
		    , T_INVENTORY.name
		    , T_INVENTORY.token_rear_side_name
		    , T_INVENTORY.active
			, v_time_start -- created_on
			, a_user_id -- created_by_user_id
			, v_time_start -- updated_last_on
			, a_user_id -- updated_last_by_user_id
		    , v_change_set_id -- change_set_id
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE
				T_INVENTORY.is_new = TRUE
			AND T_INVENTORY.active = TRUE
		;
	
		UPDATE tcg.public.TCG_MTG_Inventory INVENTORY
		SET
			  card_id = T_INVENTORY.card_id
		    , finish_id = T_INVENTORY.finish_id
		    , condition_id = T_INVENTORY.condition_id
		    , sleeve_colour_name = T_INVENTORY.sleeve_colour_name
		    , location_name = T_INVENTORY.location_name
		    , acquired_from = T_INVENTORY.acquired_from
		    , acquired_on = T_INVENTORY.acquired_on
		    , cost_gbp = T_INVENTORY.cost_gbp
		    , sale_price_gbp = T_INVENTORY.sale_price_gbp
		    , is_sold = T_INVENTORY.is_sold
		    , is_destroyed = T_INVENTORY.is_destroyed
		    , notes = T_INVENTORY.notes
		    , alterations_customisations = T_INVENTORY.alterations_customisations
		    , grading_company_name = T_INVENTORY.grading_company_name
		    , grading_score = T_INVENTORY.grading_score
		    , subgrades = T_INVENTORY.subgrades
		    , misprint_errors = T_INVENTORY.misprint_errors
		    , miscut_errors = T_INVENTORY.miscut_errors
		    , playability = T_INVENTORY.playability
		    , owner_user_id = T_INVENTORY.owner_user_id
		    , ownership_status_name = T_INVENTORY.ownership_status_name
		    , trading_status_name = T_INVENTORY.trading_status_name
		    , loaned_to_user_id = T_INVENTORY.loaned_to_user_id
		    , loan_start_on = T_INVENTORY.loan_start_on
		    , loan_end_on = T_INVENTORY.loan_end_on
		    , provenance = T_INVENTORY.provenance
		    , signed_by_names = T_INVENTORY.signed_by_names
		    , signature_condition_name = T_INVENTORY.signature_condition_name
		    , token_rear_side_card_id = T_INVENTORY.token_rear_side_card_id
		    , display_order = T_INVENTORY.display_order
		    , front_name = T_INVENTORY.name
		    , rear_name = T_INVENTORY.token_rear_side_name
		    , active = T_INVENTORY.active
			, updated_last_on = v_time_start
			, updated_last_by_user_id = a_user_id
		    , change_set_id = v_change_set_id
		FROM Temp_MTG_Inventory_Save_Inventory T_INVENTORY
		WHERE
				INVENTORY.inventory_id = T_INVENTORY.inventory_id
			AND T_INVENTORY.is_new = FALSE
		;
	ELSE
		-- Error
		INSERT INTO tcg.public.Error (
			  guid
			, error_type_id
			, message
			, display_order
			, created_on
			, created_by_user_id
			, updated_last_on
			, updated_last_by_user_id
			, change_set_id
		)
		SELECT
			  a_guid
			, T_ERROR.error_type_id
			, T_ERROR.message
			, T_ERROR.temp_id
			, v_time_start
			, a_user_id
			, v_time_start
			, a_user_id
			, v_change_set_id
		FROM Temp_MTG_Inventory_Save_Error T_ERROR
		LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON T_ERROR.error_type_id = ERROR_TYPE.error_type_id
		ORDER BY T_ERROR.temp_id
		;
	END IF;

    COMMIT;
	
	o_success := NOT EXISTS (
		SELECT *
		FROM Temp_MTG_Inventory_Save_Error T_ERROR
		WHERE T_ERROR.error_type_id <> v_warning_error_type_id
		LIMIT 1
	);
	
	DELETE FROM tcg.public.TCG_MTG_Inventory_Temp I_T WHERE I_T.guid = a_guid;

	DROP TABLE IF EXISTS Temp_MTG_Inventory_Save_Inventory;
	DROP TABLE IF EXISTS Temp_MTG_Inventory_Save_Card;
	DROP TABLE IF EXISTS Temp_MTG_Inventory_Save_Error;
/*
EXCEPTION
    WHEN OTHERS THEN
		GET STACKED DIAGNOSTICS v_error_message = MESSAGE_TEXT;
	    
	    RAISE NOTICE 'Commit failed: %', v_error_message;
	    
	    ROLLBACK;
	    
	    RAISE EXCEPTION 'Transaction failed: %', v_error_message;
*/
END;
$$;

/*
alter alter table TCG.PUBLIC.TCG_MTG_Inventory alter column  front_name set not null
alter table TCG.PUBLIC.TCG_MTG_Inventory add   rear_name TEXT

insert into TCG.PUBLIC.TCG_Change_Set (
	comment
	, updated_last_by_user_id
)
values (
	'Add names'
	, 3
);
select * from TCG.PUBLIC.TCG_Change_Set cs order by cs.change_set_id desc limit 1

with inventory_named as (
	select
		I.inventory_id
		, MAIN_C.name as front_name
		, REAR_C.name as rear_name
	from TCG.PUBLIC.TCG_MTG_Inventory I
	left join tcg.public.TCG_MTG_Card MAIN_C on I.card_id = MAIN_C.card_id
	left join tcg.public.TCG_MTG_Card REAR_C on I.token_rear_side_card_id = REAR_C.card_id
)
update TCG.PUBLIC.TCG_MTG_Inventory I
set
	change_set_id = 11
	, front_name = I_N.front_name
	, rear_name = I_N.rear_name
from inventory_named I_N
	where i.inventory_id  = I_N.inventory_id
;
ALTER TABLE tcg.public.TCG_MTG_Inventory_Temp ADD guid UUID NOT NULL

CALL tcg.public.USP_TCG_MTG_Inventory_Save (
	  'Import inventory from Spreadsheet.' -- a_comment
	, gen_random_uuid() -- a_guid
	, 3 -- a_user_id
	, TRUE -- o_success
);

SELECT *
FROM tcg.public.Error ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON ERROR.error_type_id = ERROR_TYPE.error_type_id
;
INSERT INTO tcg.public.Error_Type (
      code
    , name
    , active
    , created_by_user_id
    , updated_last_by_user_id
    , change_set_id
)
VALUES
      (
          'BAD_DATA'
        , 'Invalid data'
        , TRUE
        , 3
        , 3
        , 10
    )
    , (
          'NO_PERMISSION'
        , 'No permission'
        , TRUE
        , 3
        , 3
        , 10
    )
    , (
          'SQL_ERROR'
        , 'SQL Error'
        , TRUE
        , 3
        , 3
        , 10
    )
    , (
          'WARNING'
        , 'Warning'
        , TRUE
        , 3
        , 3
        , 10
    )
;
*/

-- Call it with:
-- CALL USP_TCG_MTG_Inventory_Save(value);
DO $$
DECLARE
	v_comment TEXT := 'Import inventory from Spreadsheet.';
	v_guid UUID;
    v_success BOOLEAN;
    v_user_id INT := 3;
BEGIN
	v_guid := gen_random_uuid();

    CALL tcg.public.USP_TCG_MTG_Inventory_Save (
		  v_comment -- a_comment
		, v_guid -- a_guid
		, v_user_id -- a_user_id
		, v_success -- o_success
	);
    RAISE NOTICE 'Success: %', CASE WHEN v_success THEN 'TRUE' ELSE 'FALSE' END;
END;
$$;

SELECT *
-- DELETE
FROM tcg.public.Error ERROR
LEFT JOIN tcg.public.Error_Type ERROR_TYPE ON ERROR.error_type_id = ERROR_TYPE.error_type_id
;
SELECT *
FROM tcg.public.Error_Type ERROR_TYPE
;
SELECT *
FROM tcg.public.TCG_Change_Set CHANGE_SET
ORDER BY CHANGE_SET.change_set_id  DESC
;

/*
SELECT COUNT(*)
from tcg.public.TCG_MTG_Inventory I
;
SELECT
--	COUNT(*)
	*
from tcg.public.TCG_MTG_Inventory_Temp I_T
;
*/

