
CREATE OR REPLACE PROCEDURE tcg.public.USP_TCG_MTG_Game_Round_Damage_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_no_permission_error_type_id INT;
	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_no_permission_error_type_id := (SELECT ERROR_TYPE.error_type_id FROM tcg.public.Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = 'NO_PERMISSION' 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_Round_Damage_Save_Game;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Player;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Round;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Round_Player_Damage;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Error;
    
    CREATE TEMP TABLE Temp_MTG_Round_Damage_Save_Game (
          game_id INT NOT NULL
        , notes TEXT
        , is_commander BOOLEAN
        , is_draft BOOLEAN
        , is_sealed BOOLEAN
        , location_name TEXT
        , start_on TIMESTAMP
        , end_on TIMESTAMP
        , active BOOLEAN
        , created_on TIMESTAMP
        , created_by_user_id INT
        , updated_last_on TIMESTAMP
        , updated_last_by_user_id INT
        , change_set_id INT
    );

    CREATE TEMP TABLE Temp_MTG_Round_Damage_Save_Player (
          player_id INT NOT NULL
        , game_id INT
        , user_id INT
        , deck_id INT
        , name TEXT
        , notes TEXT
        , display_order INT
        , active BOOLEAN
        , created_on TIMESTAMP
        , created_by_user_id INT
        , updated_last_on TIMESTAMP
        , updated_last_by_user_id INT
		, change_set_id INT
    );

    CREATE TEMP TABLE Temp_MTG_Round_Damage_Save_Round (
          temp_id INT NOT NULL
        , round_id INT
        , game_id INT
        , notes TEXT
        , display_order INT
        , active BOOLEAN
        , created_on TIMESTAMP
        , created_by_user_id INT
        , updated_last_on TIMESTAMP
        , updated_last_by_user_id INT
		, change_set_id INT

        , is_new BOOLEAN
        , error_name TEXT
        , is_duplicate BOOLEAN DEFAULT FALSE
    );

    CREATE TEMP TABLE Temp_MTG_Round_Damage_Save_Round_Player_Damage (
          temp_id INT NOT NULL
        , damage_id INT
        , temp_round_id INT
        , round_id INT
        , player_id INT
        , received_from_commander_player_id INT
        , health_change INT
        , commander_deaths INT
		, is_eliminated BOOLEAN
        , active BOOLEAN
        , created_on TIMESTAMP
        , created_by_user_id INT
        , updated_last_on TIMESTAMP
        , updated_last_by_user_id INT
		, change_set_id INT

        , is_new BOOLEAN
        , error_name TEXT
        , is_duplicate BOOLEAN DEFAULT FALSE
    );

	CREATE TEMP TABLE Temp_MTG_Round_Damage_Save_Error (
		  temp_id INT GENERATED ALWAYS AS IDENTITY
		, error_type_id INT
		, message TEXT
	);

    IF NOT EXISTS (SELECT * FROM tcg.public.TCG_User TCG_USER WHERE TCG_USER.user_id = a_user_id LIMIT 1) THEN
        INSERT INTO Temp_MTG_Round_Damage_Save_Error (
            error_type_id
            , message
        )
        VALUES (
            v_no_permission_error_type_id -- error_type_id
            , CONCAT(
                'User does not exist: '
                , CAST(a_user_id AS VARCHAR)
                , '.'
            ) -- message
        );
    END IF;
	
	INSERT INTO Temp_MTG_Round_Damage_Save_Round (
		  temp_id
        , round_id
        , game_id
        , notes
        , display_order
        , active
        , created_on
        , created_by_user_id
        , updated_last_on
        , updated_last_by_user_id

		, is_new
		, error_name
	)
	SELECT
		  ROUND_T.temp_id
        , ROUND_T.round_id
        , ROUND_T.game_id
        , ROUND_T.notes
        , ROUND_T.display_order
        , COALESCE(ROUND_T.active, TRUE)
        , COALESCE(ROUND_T.created_on, v_time_start) -- created_on
        , COALESCE(ROUND_T.created_by_user_id, a_user_id) -- created_by_user_id
        , COALESCE(ROUND_T.updated_last_on, v_time_start) -- updated_last_on
        , COALESCE(ROUND_T.updated_last_by_user_id, a_user_id) -- updated_last_by_user_id

		, CASE WHEN TCG_ROUND.round_id IS NULL THEN TRUE ELSE FALSE END AS is_new
		, CONCAT(
			  'Round { id: '
			, CAST(ROUND_T.round_id AS VARCHAR)
			, ', temp id: '
			, CAST(ROUND_T.temp_id AS VARCHAR)
			, ', display order: '
			, CAST(ROUND_T.display_order AS VARCHAR)
			, ', game id: '
			, CAST(ROUND_T.game_id AS VARCHAR)
			, ' }'
		) -- error_name
	FROM tcg.public.TCG_MTG_Game_Round_Temp ROUND_T
	LEFT JOIN tcg.public.TCG_MTG_Game_Round TCG_ROUND
		ON  ROUND_T.round_id = TCG_ROUND.round_id
		OR  (
				COALESCE(ROUND_T.round_id, 0) < 1
			AND ROUND_T.game_id = TCG_ROUND.game_id
			AND ROUND_T.display_order = TCG_ROUND.display_order
		)
	WHERE ROUND_T.guid = a_guid
	;
	
	INSERT INTO Temp_MTG_Round_Damage_Save_Round_Player_Damage (
		  temp_id
        , damage_id
        , temp_round_id
        , round_id
        , player_id
        , received_from_commander_player_id
        , health_change
        , commander_deaths
		, is_eliminated
        , active
        , created_on
        , created_by_user_id
        , updated_last_on
        , updated_last_by_user_id

		, is_new
		, error_name
	)
	SELECT
		  PLAYER_DAMAGE_T.temp_id
        , CASE WHEN COALESCE(PLAYER_DAMAGE_T.damage_id, 0) < 1 
			THEN COALESCE(PLAYER_DAMAGE.damage_id, PLAYER_DAMAGE_T.damage_id, 0)
			ELSE PLAYER_DAMAGE_T.damage_id
		END -- damage_id
        , T_ROUND.temp_id AS temp_round_id
        , PLAYER_DAMAGE_T.round_id
        , PLAYER_DAMAGE_T.player_id
        , PLAYER_DAMAGE_T.received_from_commander_player_id
        , COALESCE(PLAYER_DAMAGE_T.health_change, 0) -- health_change
        , COALESCE(PLAYER_DAMAGE_T.commander_deaths, 0) -- commander_deaths
		, COALESCE(PLAYER_DAMAGE_T.is_eliminated, FALSE) -- is_eliminated
        , COALESCE(PLAYER_DAMAGE_T.active, TRUE) -- active
        , COALESCE(PLAYER_DAMAGE_T.created_on, v_time_start) -- created_on
        , COALESCE(PLAYER_DAMAGE_T.created_by_user_id, a_user_id) -- created_by_user_id
        , COALESCE(PLAYER_DAMAGE_T.updated_last_on, v_time_start) -- updated_last_on
        , COALESCE(PLAYER_DAMAGE_T.updated_last_by_user_id, a_user_id) -- updated_last_by_user_id

		, CASE WHEN PLAYER_DAMAGE.damage_id IS NULL THEN TRUE ELSE FALSE END AS is_new
		, CONCAT(
			  'Round Player Damage { id: '
			, CAST(PLAYER_DAMAGE_T.damage_id AS VARCHAR)
			, ', temp id: '
			, CAST(PLAYER_DAMAGE_T.temp_id AS VARCHAR)
			, ', round id: '
			, CAST(PLAYER_DAMAGE_T.round_id AS VARCHAR)
			, ', player id: '
			, CAST(PLAYER_DAMAGE_T.player_id AS VARCHAR)
			, ', received from commander player id: '
			, CAST(PLAYER_DAMAGE_T.received_from_commander_player_id AS VARCHAR)
			, ', health change: '
			, CAST(PLAYER_DAMAGE_T.health_change AS VARCHAR)
			, ' }'
		) -- error_name
	FROM tcg.public.TCG_MTG_Game_Round_Player_Damage_Temp PLAYER_DAMAGE_T
	LEFT JOIN tcg.public.TCG_MTG_Game_Round_Player_Damage PLAYER_DAMAGE
		ON 	PLAYER_DAMAGE_T.damage_id = PLAYER_DAMAGE.damage_id
		OR  (
				COALESCE(PLAYER_DAMAGE_T.damage_id, 0) < 1
			AND PLAYER_DAMAGE_T.round_id = PLAYER_DAMAGE.round_id
			AND PLAYER_DAMAGE_T.player_id = PLAYER_DAMAGE.player_id
			AND (
					PLAYER_DAMAGE_T.received_from_commander_player_id = PLAYER_DAMAGE.received_from_commander_player_id
				OR  (
						PLAYER_DAMAGE_T.received_from_commander_player_id IS NULL
					AND PLAYER_DAMAGE.received_from_commander_player_id IS NULL
				)
			)
		)
    LEFT JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON PLAYER_DAMAGE_T.round_id = T_ROUND.round_id
	WHERE PLAYER_DAMAGE_T.guid = a_guid
	;

	UPDATE Temp_MTG_Round_Damage_Save_Round T_ROUND
	SET round_id = COALESCE(TCG_ROUND.round_id, T_ROUND.round_id)
	FROM tcg.public.TCG_MTG_Game_Round TCG_ROUND
	WHERE
			(
				T_ROUND.round_id = TCG_ROUND.round_id
			OR  (
					T_ROUND.game_id = TCG_ROUND.game_id
				AND T_ROUND.display_order = TCG_ROUND.display_order
			)
		)
		AND COALESCE(T_ROUND.round_id, 0) < 1
	;

	UPDATE Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
	SET damage_id = COALESCE(PLAYER_DAMAGE.damage_id, T_PLAYER_DAMAGE.damage_id, 0)
	/* FROM tcg.public.TCG_MTG_Game_Round_Player_Damage PLAYER_DAMAGE
    LEFT JOIN  */
	FROM tcg.public.TCG_MTG_Game_Round_Player_Damage PLAYER_DAMAGE
	INNER JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON PLAYER_DAMAGE.round_id = T_ROUND.round_id
	WHERE
			( 
			 	T_PLAYER_DAMAGE.damage_id = PLAYER_DAMAGE.damage_id
			OR  (
					T_ROUND.round_id = PLAYER_DAMAGE.round_id
				AND T_PLAYER_DAMAGE.player_id = PLAYER_DAMAGE.player_id
				AND (
						T_PLAYER_DAMAGE.received_from_commander_player_id = PLAYER_DAMAGE.received_from_commander_player_id
					OR  (
							T_PLAYER_DAMAGE.received_from_commander_player_id IS NULL
						AND PLAYER_DAMAGE.received_from_commander_player_id IS NULL
					)
				)
			)
		)
		AND T_PLAYER_DAMAGE.temp_round_id = T_ROUND.temp_id
		AND COALESCE(T_PLAYER_DAMAGE.damage_id, 0) < 1
	;
	
    INSERT INTO Temp_MTG_Round_Damage_Save_Game (
          game_id
        , notes
        , is_commander
        , is_draft
        , is_sealed
        , location_name
        , start_on
        , end_on
        , active
        , created_on
        , created_by_user_id
        , updated_last_on
        , updated_last_by_user_id
        , change_set_id
    )
	SELECT DISTINCT
		  GAME.game_id
        , GAME.notes
        , GAME.is_commander
        , GAME.is_draft
        , GAME.is_sealed
        , GAME.location_name
        , GAME.start_on
        , GAME.end_on
        , GAME.active
        , GAME.created_on
        , GAME.created_by_user_id
        , GAME.updated_last_on
        , GAME.updated_last_by_user_id
        , GAME.change_set_id
	FROM tcg.public.TCG_MTG_Game GAME
	INNER JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON GAME.game_id = T_ROUND.game_id
	;
	
	INSERT INTO Temp_MTG_Round_Damage_Save_Player (
		  player_id
        , game_id
        , user_id
        , deck_id
        , name
        , notes
        , display_order
        , active
        , created_on
        , created_by_user_id
        , updated_last_on
        , updated_last_by_user_id
		, change_set_id
	)
	SELECT DISTINCT
		  PLAYER.player_id
        , PLAYER.game_id
        , PLAYER.user_id
        , PLAYER.deck_id
        , PLAYER.name
        , PLAYER.notes
        , PLAYER.display_order
        , PLAYER.active
        , PLAYER.created_on
        , PLAYER.created_by_user_id
        , PLAYER.updated_last_on
        , PLAYER.updated_last_by_user_id
        , PLAYER.change_set_id
	FROM tcg.public.TCG_MTG_Game_Player PLAYER
	INNER JOIN Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        ON  PLAYER.player_id = T_PLAYER_DAMAGE.player_id
        OR  PLAYER.player_id = T_PLAYER_DAMAGE.received_from_commander_player_id
	;
    
	/*
					INSERT INTO Temp_MTG_Round_Damage_Save_Error (
						  error_type_id
						, message
					)
					SELECT
						  v_bad_data_error_type_id -- error_type_id
						, CONCAT(
							'Rounds: '
							, STRING_AGG(T_ROUND.error_name, ', ')
							, '.'
						) -- message
					FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
					;
	*/

    -- Validate Round
	-- Missing fields
	WITH Round_Missing_Field AS (
        SELECT
              T_ROUND.temp_id
            , 'game_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
        WHERE T_ROUND.game_id IS NULL
    )
	INSERT INTO Temp_MTG_Round_Damage_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Missing mandatory field: '
			, ROUND_MISSING_FIELD.field
			, ' on '
			, T_ROUND.error_name
			, '.'
		) -- message
	FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
	INNER JOIN Round_Missing_Field ROUND_MISSING_FIELD ON T_ROUND.temp_id = ROUND_MISSING_FIELD.temp_id
	;

	-- Failed join fields
	WITH Round_Failed_Join_Field AS (
        SELECT
              T_ROUND.temp_id
            , 'game_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
        LEFT JOIN Temp_MTG_Round_Damage_Save_Game T_GAME ON T_ROUND.game_id = T_GAME.game_id
        WHERE T_GAME.game_id IS NULL
    )
	INSERT INTO Temp_MTG_Round_Damage_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Failed relationship: '
			, ROUND_FAILED_JOIN_FIELD.field
			, ' on '
			, T_ROUND.error_name
			, '.'
		) -- message
	FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
	INNER JOIN Round_Failed_Join_Field ROUND_FAILED_JOIN_FIELD ON T_ROUND.temp_id = ROUND_FAILED_JOIN_FIELD.temp_id
	;

	-- Duplicate
	WITH 
		  Existing_Round AS (
			SELECT
				  TCG_ROUND.round_id
                , TCG_ROUND.game_id
                , TCG_ROUND.display_order
			FROM tcg.public.TCG_MTG_Game_Round TCG_ROUND
            LEFT JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON TCG_ROUND.round_id = T_ROUND.round_id
            WHERE
                    TCG_ROUND.active
				/*
				AND NOT EXISTS (
					SELECT 1
					FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
					WHERE T_ROUND.round_id = TCG_ROUND.round_id
				)
				*/
				AND T_ROUND.temp_id IS NULL
		)
		, All_Round AS (
			SELECT
				  T_ROUND.temp_id
                , T_ROUND.game_id
                , T_ROUND.display_order
                , TRUE AS is_save_record
			FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
            UNION
			SELECT
				  NULL AS temp_id
                , EXISTING_ROUND.game_id
                , EXISTING_ROUND.display_order
                , FALSE AS is_save_record
			FROM Existing_Round EXISTING_ROUND
		)
		, Unique_Game_Round AS (
			SELECT
				  ALL_ROUND.game_id
                , ALL_ROUND.display_order
                , COUNT(*) AS count_rounds
			FROM All_Round ALL_ROUND
            GROUP BY
                  ALL_ROUND.game_id
                , ALL_ROUND.display_order
		)
	UPDATE Temp_MTG_Round_Damage_Save_Round T_ROUND
	SET is_duplicate = CASE WHEN COALESCE(UNIQUE_GAME_ROUND.count_rounds, 0) > 1 THEN TRUE ELSE FALSE END
	FROM Unique_Game_Round UNIQUE_GAME_ROUND
	WHERE
            T_ROUND.game_id = UNIQUE_GAME_ROUND.game_id
        AND T_ROUND.display_order = UNIQUE_GAME_ROUND.display_order
	;
	
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
		WHERE T_ROUND.is_duplicate
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Round_Damage_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Duplicate on '
				, T_ROUND.error_name
			) -- message
		FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
		WHERE T_ROUND.is_duplicate
		;
	END IF;
    

	/*
	-- Testing TESTING
	
	WITH 
		  Existing_Round AS (
			SELECT
				  TCG_ROUND.round_id
                , TCG_ROUND.game_id
                , TCG_ROUND.display_order
			FROM tcg.public.TCG_MTG_Game_Round TCG_ROUND
            LEFT JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON TCG_ROUND.round_id = T_ROUND.round_id
            WHERE
                    TCG_ROUND.active
				/*
				AND NOT EXISTS (
					SELECT *
					FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
					WHERE T_ROUND.round_id = TCG_ROUND.round_id
				)
				*/
				AND T_ROUND.temp_id IS NULL
		)
		, All_Round AS (
			SELECT
				  T_ROUND.temp_id
                , T_ROUND.round_id
                , T_ROUND.game_id
                , T_ROUND.display_order
                , TRUE AS is_save_record
			FROM Temp_MTG_Round_Damage_Save_Round T_ROUND
            UNION
			SELECT
				  NULL AS temp_id
                , EXISTING_ROUND.round_id
                , EXISTING_ROUND.game_id
                , EXISTING_ROUND.display_order
                , FALSE AS is_save_record
			FROM Existing_Round EXISTING_ROUND
		)
		, Unique_Game_Round AS (
			SELECT
				  ALL_ROUND.game_id
                , ALL_ROUND.display_order
                , COUNT(*) AS count_rounds
			FROM All_Round ALL_ROUND
            GROUP BY
                  ALL_ROUND.game_id
                , ALL_ROUND.display_order
		)
	INSERT INTO Temp_MTG_Round_Damage_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			  'TEST: Existing rounds: '
			, STRING_AGG(
				CONCAT(
					  '{ Round ID: '
					, CAST(EXISTING_ROUND.round_id AS VARCHAR)
					, ', Game ID: '
					, CAST(EXISTING_ROUND.game_id AS VARCHAR)
					, ', Display order: '
					, CAST(EXISTING_ROUND.display_order AS VARCHAR)
					, ' }'
				)
				, ', '
			)
		) -- message
	FROM Existing_Round EXISTING_ROUND
	UNION
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			  'TEST: All rounds: '
		--	, STRING_AGG(CONCAT(ALL_ROUND.temp_id, ' - ', ALL_ROUND.game_id, ' - ', ALL_ROUND.display_order), ', ')
			, STRING_AGG(
				CONCAT(
					  '{ Temp ID: '
					, CAST(ALL_ROUND.temp_id AS VARCHAR)
					, ', Round ID: '
					, CAST(ALL_ROUND.round_id AS VARCHAR)
					, ', Game ID: '
					, CAST(ALL_ROUND.game_id AS VARCHAR)
					, ', Display order: '
					, CAST(ALL_ROUND.display_order AS VARCHAR)
					, ' }'
				)
				, ', '
			)
		) -- message
	FROM All_Round ALL_ROUND
	UNION
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			  'TEST: Unique rounds: '
		--	, STRING_AGG(CONCAT(UNIQUE_ROUND.game_id, ' - ', UNIQUE_ROUND.display_order, ' - ', UNIQUE_ROUND.count_rounds), ', ')
			, STRING_AGG(
				CONCAT(
					  '{ Game ID: '
					, CAST(UNIQUE_ROUND.game_id AS VARCHAR)
					, ', Display order: '
					, CAST(UNIQUE_ROUND.display_order AS VARCHAR)
					, ' Count: '
					, CAST(UNIQUE_ROUND.count_rounds AS VARCHAR)
					, ' }'
				)
				, ', '
			)
		) -- message
	FROM Unique_Game_Round UNIQUE_ROUND
	;
	*/

    -- Validate Damage
	-- Missing fields
	WITH Player_Damage_Missing_Field AS (
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'round_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        WHERE T_PLAYER_DAMAGE.round_id IS NULL
        UNION
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'player_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        WHERE T_PLAYER_DAMAGE.player_id IS NULL
        UNION
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'health_change' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        WHERE T_PLAYER_DAMAGE.health_change IS NULL
        UNION
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'commander_deaths' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        WHERE T_PLAYER_DAMAGE.commander_deaths IS NULL
    )
	INSERT INTO Temp_MTG_Round_Damage_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Missing mandatory field: '
			, PLAYER_DAMAGE_MISSING_FIELD.field
			, ' on '
			, T_PLAYER_DAMAGE.error_name
			, '.'
		) -- message
	FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
	INNER JOIN Player_Damage_Missing_Field PLAYER_DAMAGE_MISSING_FIELD ON T_PLAYER_DAMAGE.temp_id = PLAYER_DAMAGE_MISSING_FIELD.temp_id
	;

	-- Failed join fields
	WITH Player_Failed_Join_Field AS (
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'round_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        LEFT JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON T_PLAYER_DAMAGE.temp_round_id = T_ROUND.temp_id
        WHERE T_ROUND.round_id IS NULL
        UNION
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'player_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        LEFT JOIN Temp_MTG_Round_Damage_Save_Player T_PLAYER ON T_PLAYER_DAMAGE.player_id = T_PLAYER.player_id
        WHERE T_PLAYER.player_id IS NULL
        UNION
        SELECT
              T_PLAYER_DAMAGE.temp_id
            , 'received_from_commander_player_id' AS field
        FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        LEFT JOIN Temp_MTG_Round_Damage_Save_Player T_PLAYER ON T_PLAYER_DAMAGE.received_from_commander_player_id = T_PLAYER.player_id
        WHERE
				T_PLAYER.player_id IS NULL
			AND T_PLAYER_DAMAGE.received_from_commander_player_id IS NOT NULL
    )
	INSERT INTO Temp_MTG_Round_Damage_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Failed relationship: '
			, PLAYER_FAILED_JOIN_FIELD.field
			, ' on '
			, T_PLAYER_DAMAGE.error_name
			, '.'
		) -- message
	FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
	INNER JOIN Player_Failed_Join_Field PLAYER_FAILED_JOIN_FIELD ON T_PLAYER_DAMAGE.temp_id = PLAYER_FAILED_JOIN_FIELD.temp_id
	;

	-- Duplicate Round Player Damage
	WITH 
		  Existing_Player_Damage AS (
			SELECT
				  T_PLAYER_DAMAGE.round_id
                , T_PLAYER_DAMAGE.player_id
                , COALESCE(T_PLAYER_DAMAGE.received_from_commander_player_id, 0) AS received_from_commander_player_id
			FROM tcg.public.TCG_MTG_Game_Round_Player_Damage PLAYER_DAMAGE
            LEFT JOIN Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE ON PLAYER_DAMAGE.damage_id = T_PLAYER_DAMAGE.damage_id
            WHERE
                    T_PLAYER_DAMAGE.temp_id IS NULL
                AND PLAYER_DAMAGE.active
		)
		, All_Player_Damage AS (
			SELECT
				  T_PLAYER_DAMAGE.temp_id
                , T_PLAYER_DAMAGE.round_id
                , T_PLAYER_DAMAGE.player_id
                , COALESCE(T_PLAYER_DAMAGE.received_from_commander_player_id, 0) AS received_from_commander_player_id
                , TRUE AS is_save_record
			FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
            UNION
			SELECT
				  NULL AS temp_id
                , EXISTING_PLAYER_DAMAGE.round_id
                , EXISTING_PLAYER_DAMAGE.player_id
                , EXISTING_PLAYER_DAMAGE.received_from_commander_player_id
                , FALSE AS is_save_record
			FROM Existing_Player_Damage EXISTING_PLAYER_DAMAGE
		)
		, Unique_Game_Player_Damage AS (
			SELECT
                  ALL_PLAYER_DAMAGE.round_id
                , ALL_PLAYER_DAMAGE.player_id
                , ALL_PLAYER_DAMAGE.received_from_commander_player_id
                , COUNT(*) AS count_damage
			FROM All_Player_Damage ALL_PLAYER_DAMAGE
            GROUP BY
                  ALL_PLAYER_DAMAGE.round_id
                , ALL_PLAYER_DAMAGE.player_id
                , ALL_PLAYER_DAMAGE.received_from_commander_player_id
		)
	UPDATE Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
	SET is_duplicate = CASE WHEN COALESCE(UNIQUE_PLAYER_DAMAGE.count_damage, 0) > 1 THEN TRUE ELSE FALSE END
	FROM Unique_Game_Player_Damage UNIQUE_PLAYER_DAMAGE
	WHERE
        	T_PLAYER_DAMAGE.round_id = UNIQUE_PLAYER_DAMAGE.round_id
        AND T_PLAYER_DAMAGE.player_id = UNIQUE_PLAYER_DAMAGE.player_id
        AND COALESCE(T_PLAYER_DAMAGE.received_from_commander_player_id, 0) = UNIQUE_PLAYER_DAMAGE.received_from_commander_player_id
	;
	
	IF EXISTS (
		SELECT *
		FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
		WHERE T_PLAYER_DAMAGE.is_duplicate
		LIMIT 1
	) THEN
		INSERT INTO Temp_MTG_Round_Damage_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Duplicate on '
				, T_PLAYER_DAMAGE.error_name
			) -- message
		FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
		WHERE T_PLAYER_DAMAGE.is_duplicate
		;
	END IF;

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

	-- Outputs
	/*
	INSERT INTO Temp_MTG_Round_Damage_Save_Error (
		  error_type_id
		, message
	)
	VALUES
		(
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				'Temp round ids: '
				, (SELECT STRING_AGG(CAST(T_ROUND.temp_id AS VARCHAR), ',') FROM Temp_MTG_Round_Damage_Save_Round T_ROUND)
			) -- message
		)
		, (
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				'Temp player damage ids: '
				, (SELECT STRING_AGG(CAST(T_PLAYER_DAMAGE.temp_id AS VARCHAR), ',') FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE)
			) -- message
		)
		, (
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				'Temp player ids: '
				, (SELECT STRING_AGG(CAST(T_PLAYER.player_id AS VARCHAR), ',') FROM Temp_MTG_Round_Damage_Save_Player T_PLAYER)
			) -- message
		)
		, (
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				'Temp game ids: '
				, (SELECT STRING_AGG(CAST(T_GAME.game_id AS VARCHAR), ',') FROM Temp_MTG_Round_Damage_Save_Game T_GAME)
			) -- message
		)
		, (
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				'Query player damage ids: '
				, (
					SELECT STRING_AGG(CAST(T_PLAYER_DAMAGE.temp_id AS VARCHAR), ',')
					FROM Temp_MTG_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
			        INNER JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON T_PLAYER_DAMAGE.temp_round_id = T_ROUND.temp_id
			        LEFT JOIN Temp_MTG_Round_Damage_Save_Game T_GAME ON T_ROUND.game_id = T_GAME.game_id
			        LEFT JOIN Temp_MTG_Round_Damage_Save_Player T_PLAYER ON T_PLAYER_DAMAGE.player_id = T_PLAYER.player_id
				)
			) -- message
		)
	;
	*/

	-- 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_Round_Damage_Save_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
		
		-- Round
		INSERT INTO tcg.public.TCG_MTG_Game_Round (
              game_id
            , notes
            , display_order
            , active
            , created_on
            , created_by_user_id
            , updated_last_on
            , updated_last_by_user_id
            , change_set_id
		)
		SELECT
			  T_ROUND.game_id
            , T_ROUND.notes
            , T_ROUND.display_order
		    , T_ROUND.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_Round_Damage_Save_Round T_ROUND
        LEFT JOIN Temp_MTG_Round_Damage_Save_Game T_GAME ON T_ROUND.game_id = T_GAME.game_id
		WHERE
				T_ROUND.is_new = TRUE
			AND T_ROUND.active = TRUE
		ORDER BY
              T_GAME.created_on
            , T_ROUND.display_order
		;
	
		UPDATE tcg.public.TCG_MTG_Game_Round TCG_ROUND
		SET
              game_id = T_ROUND.game_id
            , notes = T_ROUND.notes
            , display_order = T_ROUND.display_order
		    , active = T_ROUND.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_Round_Damage_Save_Round T_ROUND
		WHERE
				TCG_ROUND.round_id = T_ROUND.round_id
			AND NOT T_ROUND.is_new
		;

        UPDATE Temp_MTG_Round_Damage_Save_Round T_ROUND
        SET round_id = TCG_ROUND.round_id
        FROM tcg.public.TCG_MTG_Game_Round TCG_ROUND
        WHERE
                T_ROUND.game_id = TCG_ROUND.game_id
            AND T_ROUND.display_order = TCG_ROUND.display_order
            AND T_ROUND.is_new
        ;

		-- Round Player Damage
		INSERT INTO tcg.public.TCG_MTG_Game_Round_Player_Damage (
              round_id
            , player_id
            , received_from_commander_player_id
            , health_change
            , commander_deaths
			, is_eliminated
            , active
            , created_on
            , created_by_user_id
            , updated_last_on
            , updated_last_by_user_id
            , change_set_id
		)
		SELECT
			  T_ROUND.round_id
            , T_PLAYER_DAMAGE.player_id
            , T_PLAYER_DAMAGE.received_from_commander_player_id
		    , T_PLAYER_DAMAGE.health_change
		    , T_PLAYER_DAMAGE.commander_deaths
			, T_PLAYER_DAMAGE.is_eliminated
		    , T_PLAYER_DAMAGE.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_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        INNER JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON T_PLAYER_DAMAGE.temp_round_id = T_ROUND.temp_id
        LEFT JOIN Temp_MTG_Round_Damage_Save_Game T_GAME ON T_ROUND.game_id = T_GAME.game_id
        LEFT JOIN Temp_MTG_Round_Damage_Save_Player T_PLAYER ON T_PLAYER_DAMAGE.player_id = T_PLAYER.player_id
		WHERE
				T_PLAYER_DAMAGE.is_new = TRUE
			AND T_PLAYER_DAMAGE.active = TRUE
		ORDER BY
              T_GAME.created_on
			, T_ROUND.display_order
			, T_PLAYER.display_order
		;
	
		UPDATE tcg.public.TCG_MTG_Game_Round_Player_Damage PLAYER_DAMAGE
		SET
              round_id = T_ROUND.round_id
            , player_id = T_PLAYER_DAMAGE.player_id
            , received_from_commander_player_id = T_PLAYER_DAMAGE.received_from_commander_player_id
		    , health_change = T_PLAYER_DAMAGE.health_change
		    , commander_deaths = T_PLAYER_DAMAGE.commander_deaths
			, is_eliminated = T_PLAYER_DAMAGE.is_eliminated
		    , active = T_PLAYER_DAMAGE.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_Round_Damage_Save_Round_Player_Damage T_PLAYER_DAMAGE
        INNER JOIN Temp_MTG_Round_Damage_Save_Round T_ROUND ON T_PLAYER_DAMAGE.temp_round_id = T_ROUND.temp_id
		WHERE
				PLAYER_DAMAGE.damage_id = T_PLAYER_DAMAGE.damage_id
			AND NOT T_PLAYER_DAMAGE.is_new
		;
	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_Round_Damage_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_Round_Damage_Save_Error T_ERROR
		WHERE T_ERROR.error_type_id <> v_warning_error_type_id
		LIMIT 1
	);
	
	DELETE FROM tcg.public.TCG_MTG_Game_Round_Temp ROUND_T WHERE ROUND_T.guid = a_guid;
	DELETE FROM tcg.public.TCG_MTG_Game_Round_Player_Damage_Temp ROUND_DAMAGE_T WHERE ROUND_DAMAGE_T.guid = a_guid;

	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Game;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Player;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Round;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Round_Player_Damage;
	DROP TABLE IF EXISTS Temp_MTG_Round_Damage_Save_Error;
END;
$$;

-- Call it with:
DO $$
DECLARE
	v_comment TEXT := 'MTG Game Round Player Damage Save.';
	v_guid UUID;
    v_user_id INT := 3;
    v_success BOOLEAN;
BEGIN
	v_guid := '6307bed6-73a1-41ab-9a90-79e18e14dd81'::UUID; -- gen_random_uuid();

    CALL tcg.public.USP_TCG_MTG_Game_Round_Damage_Save (
		  a_comment := v_comment -- a_comment
		, a_guid := v_guid -- a_guid
		, a_user_id := v_user_id -- a_user_id
		, o_success := 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 *
FROM tcg.public.TCG_MTG_Game
;
;
*/
SELECT *
-- DELETE
FROM tcg.public.TCG_MTG_Game_Round_Temp
;
SELECT *
-- DELETE
FROM tcg.public.TCG_MTG_Game_Round_Player_Damage_Temp
;
SELECT *
-- DELETE
FROM tcg.public.TCG_MTG_Game_Round TCG_ROUND
LEFT JOIN tcg.public.TCG_MTG_Game GAME ON TCG_ROUND.game_id = GAME.game_id
;
SELECT *
-- DELETE
FROM tcg.public.TCG_MTG_Game_Round_Player_Damage PLAYER_DAMAGE
LEFT JOIN tcg.public.TCG_MTG_Game_Round TCG_ROUND ON PLAYER_DAMAGE.round_id = TCG_ROUND.round_id
LEFT JOIN tcg.public.TCG_MTG_Game GAME ON TCG_ROUND.game_id = GAME.game_id
;



	/*
	INSERT INTO tcg.public.TCG_MTG_Game_Round_Temp (
		  guid
	    , round_id
        , game_id
        , notes
        , display_order
        , active
	)
	VALUES (
          v_guid -- guid
        , -1 -- round_id
        , 4 -- game_id
        , 'Beaten' -- notes
        , 5 -- display_order
        , TRUE -- active
    )
    ;

	INSERT INTO tcg.public.TCG_MTG_Game_Round_Player_Damage_Temp (
		  guid
        , damage_id
        , round_id
        , player_id
        , received_from_commander_player_id
        , health_change
        , commander_deaths
        , active
	)
	VALUES
          (
              v_guid -- guid
            , NULL -- damage_id
            , -1 -- round_id
            , 3 -- player_id
            , NULL -- received_from_commander_player_id
            , -4 -- health_change
            , 1 -- commander_deaths
            , TRUE -- active
        )
		, (
              v_guid -- guid
            , NULL -- damage_id
            , -1 -- round_id
            , 3 -- player_id
            , 2 -- received_from_commander_player_id
            , -5 -- health_change
            , NULL -- commander_deaths
            , TRUE -- active
        )
		, (
              v_guid -- guid
            , NULL -- damage_id
            , -1 -- round_id
            , 3 -- player_id
            , 5 -- received_from_commander_player_id
            , -6 -- health_change
            , NULL -- commander_deaths
            , TRUE -- active
        )
    ;
	*/




