
CREATE OR REPLACE PROCEDURE tcg.public.USP_TCG_User_Relationship_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_comment TEXT;
	-- v_error_message TEXT;
    v_guid UUID;
	v_time_start TIMESTAMP;
    v_user_id INT;
	v_warning_error_type_id INT;
BEGIN
    v_comment := TRIM(COALESCE(a_comment, ''));
    v_guid := a_guid;
    v_user_id := a_user_id;

	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_User_Relationship_Save_User;
	DROP TABLE IF EXISTS Temp_User_Relationship_Save_User_Relationship;
	DROP TABLE IF EXISTS Temp_User_Relationship_Save_Error;
        
    CREATE TEMP TABLE Temp_User_Relationship_Save_User (
          user_id INT NOT NULL
        , user_auth0_id TEXT
        , firstname TEXT
        , surname TEXT
        , email TEXT
        , is_email_verified BOOLEAN
        , is_super_user 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
    );

    CREATE TEMP TABLE Temp_User_Relationship_Save_User_Relationship (
          temp_id INT NOT NULL
		, relationship_id INT
        , follower_user_id INT
        , following_user_id INT
        , is_following BOOLEAN
        , is_blocked 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
    );

	CREATE TEMP TABLE Temp_User_Relationship_Save_Error (
		  temp_id INT GENERATED ALWAYS AS IDENTITY
		, error_type_id INT
		, message TEXT
	);
	
	WITH Temp_User_Relationship AS (
		SELECT
	          RELATIONSHIP_T.temp_id
	        , CASE WHEN COALESCE(RELATIONSHIP_T.relationship_id, 0) < 1
				THEN RELATIONSHIP.relationship_id
				ELSE RELATIONSHIP_T.relationship_id
			END AS relationship_id
	        , RELATIONSHIP_T.follower_user_id
	        , RELATIONSHIP_T.following_user_id
	        , COALESCE(RELATIONSHIP_T.is_following, TRUE) AS is_following
	        , COALESCE(RELATIONSHIP_T.is_blocked, FALSE) AS is_blocked
	        , COALESCE(RELATIONSHIP_T.active, TRUE) AS active
	        , COALESCE(RELATIONSHIP_T.created_on, v_time_start) AS created_on
	        , COALESCE(RELATIONSHIP_T.created_by_user_id, v_user_id) AS created_by_user_id
	        , COALESCE(RELATIONSHIP_T.updated_last_on, v_time_start) AS updated_last_on
	        , COALESCE(RELATIONSHIP_T.updated_last_by_user_id, v_user_id) AS updated_last_by_user_id
	        , RELATIONSHIP_T.change_set_id
	
	        , CASE WHEN RELATIONSHIP.relationship_id IS NULL THEN TRUE ELSE FALSE END AS is_new
		FROM tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T
	    LEFT JOIN tcg.public.TCG_User_Relationship RELATIONSHIP
			ON  RELATIONSHIP_T.relationship_id = RELATIONSHIP.relationship_id
			OR  (
					COALESCE(RELATIONSHIP_T.relationship_id, 0) < 1
				AND RELATIONSHIP_T.follower_user_id = RELATIONSHIP.follower_user_id
				AND RELATIONSHIP_T.following_user_id = RELATIONSHIP.following_user_id
			)
	)
    INSERT INTO Temp_User_Relationship_Save_User_Relationship (
          temp_id
		, relationship_id
        , follower_user_id
        , following_user_id
        , is_following
        , is_blocked
        , active
        , created_on
        , created_by_user_id
        , updated_last_on
        , updated_last_by_user_id
        , change_set_id

        , is_new
		, error_name
    )
	SELECT
          T_RELATIONSHIP.temp_id
        , T_RELATIONSHIP.relationship_id
        , T_RELATIONSHIP.follower_user_id
        , T_RELATIONSHIP.following_user_id
        , T_RELATIONSHIP.is_following
        , T_RELATIONSHIP.is_blocked
        , T_RELATIONSHIP.active
        , T_RELATIONSHIP.created_on
        , T_RELATIONSHIP.created_by_user_id
        , T_RELATIONSHIP.updated_last_on
        , T_RELATIONSHIP.updated_last_by_user_id
        , T_RELATIONSHIP.change_set_id

        , T_RELATIONSHIP.is_new
		, CONCAT(
			  'User Relationship { id: '
			, CAST(T_RELATIONSHIP.relationship_id AS VARCHAR)
			, ', follower user id: '
			, CAST(T_RELATIONSHIP.follower_user_id AS VARCHAR)
			, ', following user id: '
			, CAST(T_RELATIONSHIP.following_user_id AS VARCHAR)
			, ', is following: '
			, CAST(T_RELATIONSHIP.is_following AS VARCHAR)
			, ', is blocked: '
			, CAST(T_RELATIONSHIP.is_blocked AS VARCHAR)
			, ' }'
		) -- error_name
	FROM Temp_User_Relationship T_RELATIONSHIP -- tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T
    -- LEFT JOIN tcg.public.TCG_User_Relationship RELATIONSHIP ON RELATIONSHIP_T.relationship_id = RELATIONSHIP.relationship_id
	;

    INSERT INTO Temp_User_Relationship_Save_User (
          user_id
        , user_auth0_id
        , firstname
        , surname
        , email
        , is_email_verified
        , is_super_user
        , active
        , created_on
        , created_by_user_id
        , updated_last_on
        , updated_last_by_user_id
        , change_set_id
    )
	SELECT
          TCG_USER.user_id
        , TCG_USER.user_auth0_id
        , TCG_USER.firstname
        , TCG_USER.surname
        , TCG_USER.email
        , TCG_USER.is_email_verified
        , TCG_USER.is_super_user
        , TCG_USER.active
        , TCG_USER.created_on
        , TCG_USER.created_by_user_id
        , TCG_USER.updated_last_on
        , TCG_USER.updated_last_by_user_id
        , TCG_USER.change_set_id
	FROM tcg.public.TCG_User TCG_USER
	INNER JOIN Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
        ON  TCG_USER.user_id = T_RELATIONSHIP.follower_user_id
        OR  TCG_USER.user_id = T_RELATIONSHIP.following_user_id
	;

	-- Missing fields
	WITH Relationship_Missing_Field AS (
        SELECT
              T_RELATIONSHIP.temp_id
            , 'follower_user_id' AS field
        FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
        WHERE T_RELATIONSHIP.follower_user_id IS NULL
        UNION
        SELECT
              T_RELATIONSHIP.temp_id
            , 'following_user_id' AS field
        FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
        WHERE T_RELATIONSHIP.following_user_id IS NULL
    )
	INSERT INTO Temp_User_Relationship_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Missing mandatory field: '
			, RELATIONSHIP_MISSING_FIELD.field
			, ' on '
			, T_RELATIONSHIP.error_name
			, '.'
		) -- message
	FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
	INNER JOIN Relationship_Missing_Field RELATIONSHIP_MISSING_FIELD ON T_RELATIONSHIP.temp_id = RELATIONSHIP_MISSING_FIELD.temp_id
	;

	-- Failed join fields
	WITH Relationship_Failed_Join_Field AS (
        SELECT
              T_RELATIONSHIP.temp_id
            , 'follower_user_id' AS field
        FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
        LEFT JOIN Temp_User_Relationship_Save_User T_USER ON T_RELATIONSHIP.follower_user_id = T_USER.user_id
        WHERE T_USER.user_id IS NULL
        UNION
        SELECT
              T_RELATIONSHIP.temp_id
            , 'following_user_id' AS field
        FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
        LEFT JOIN Temp_User_Relationship_Save_User T_USER ON T_RELATIONSHIP.following_user_id = T_USER.user_id
        WHERE T_USER.user_id IS NULL
    )
	INSERT INTO Temp_User_Relationship_Save_Error (
		  error_type_id
		, message
	)
	SELECT
		  v_bad_data_error_type_id -- error_type_id
		, CONCAT(
			'Failed relationship: '
			, RELATIONSHIP_FAILED_JOIN_FIELD.field
			, ' on '
			, T_RELATIONSHIP.error_name
			, '.'
		) -- message
	FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
	INNER JOIN Relationship_Failed_Join_Field RELATIONSHIP_FAILED_JOIN_FIELD ON T_RELATIONSHIP.temp_id = RELATIONSHIP_FAILED_JOIN_FIELD.temp_id
	;

	-- Duplicate Relationship
	WITH 
		  All_Relationship AS (
			SELECT
				  T_RELATIONSHIP.temp_id
                , T_RELATIONSHIP.follower_user_id
                , T_RELATIONSHIP.following_user_id
                , TRUE AS is_save_record
			FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
            UNION
			SELECT
				  NULL AS temp_id
                , RELATIONSHIP.follower_user_id
                , RELATIONSHIP.following_user_id
                , FALSE AS is_save_record
			FROM tcg.public.TCG_User_Relationship RELATIONSHIP
            LEFT JOIN Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP ON RELATIONSHIP.relationship_id = T_RELATIONSHIP.relationship_id
            WHERE
                    T_RELATIONSHIP.relationship_id IS NULL
                AND RELATIONSHIP.active
		)
		, Relationship_Follow_Pair AS (
			SELECT
				  ALL_RELATIONSHIP.follower_user_id
                , ALL_RELATIONSHIP.following_user_id
                , COUNT(*) AS count_pair
			FROM All_Relationship ALL_RELATIONSHIP
            GROUP BY
                  ALL_RELATIONSHIP.follower_user_id
                , ALL_RELATIONSHIP.following_user_id
		)
		, Duplicate_Relationship AS (
			SELECT
				  ALL_RELATIONSHIP.temp_id
                , ALL_RELATIONSHIP.follower_user_id
                , ALL_RELATIONSHIP.following_user_id
                , CASE WHEN RELATIONSHIP_PAIR.count_pair = 1 THEN TRUE ELSE FALSE END AS is_unique
			FROM All_Relationship ALL_RELATIONSHIP
            INNER JOIN Relationship_Follow_Pair RELATIONSHIP_PAIR
                ON  ALL_RELATIONSHIP.follower_user_id = RELATIONSHIP_PAIR.follower_user_id
                AND ALL_RELATIONSHIP.following_user_id = RELATIONSHIP_PAIR.following_user_id
		)
	UPDATE Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
	SET is_duplicate = NOT DUPLICATE_RELATIONSHIP.is_unique
	FROM Duplicate_Relationship DUPLICATE_RELATIONSHIP
	WHERE T_RELATIONSHIP.temp_id = DUPLICATE_RELATIONSHIP.temp_id
	;
	
	IF EXISTS (
		SELECT *
		FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
		WHERE T_RELATIONSHIP.is_duplicate
		LIMIT 1
	) THEN
		INSERT INTO Temp_User_Relationship_Save_Error (
			  error_type_id
			, message
		)
		SELECT
			  v_bad_data_error_type_id -- error_type_id
			, CONCAT(
				  'Duplicate on '
				, T_RELATIONSHIP.error_name
			) -- message
		FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
		WHERE T_RELATIONSHIP.is_duplicate
		;
	END IF;

	-- Nothing to save
	IF NOT EXISTS (SELECT * FROM Temp_User_Relationship_Save_User_Relationship LIMIT 1) THEN
		INSERT INTO Temp_User_Relationship_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 (
		  v_comment
		, v_user_id
	)
	RETURNING change_set_id INTO v_change_set_id
	;
	
	IF NOT EXISTS (SELECT * FROM Temp_User_Relationship_Save_Error T_ERROR WHERE T_ERROR.error_type_id <> v_warning_error_type_id LIMIT 1) THEN
		
		-- User relationship
		INSERT INTO tcg.public.TCG_User_Relationship (
              follower_user_id
            , following_user_id
            , is_following
            , is_blocked
            , active
            , created_on
            , created_by_user_id
            , updated_last_on
            , updated_last_by_user_id
            , change_set_id
		)
		SELECT
			  T_RELATIONSHIP.follower_user_id
            , T_RELATIONSHIP.following_user_id
            , T_RELATIONSHIP.is_following
            , T_RELATIONSHIP.is_blocked
		    , T_RELATIONSHIP.active
            , T_RELATIONSHIP.created_on
            , T_RELATIONSHIP.created_by_user_id
            , T_RELATIONSHIP.updated_last_on
		    , T_RELATIONSHIP.updated_last_by_user_id
            , v_change_set_id -- change_set_id
		FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
		WHERE
				T_RELATIONSHIP.is_new = TRUE
			AND T_RELATIONSHIP.active = TRUE
        ORDER BY
              T_RELATIONSHIP.is_following
            , T_RELATIONSHIP.is_blocked
            , T_RELATIONSHIP.follower_user_id
            , T_RELATIONSHIP.following_user_id
		;
	
		UPDATE tcg.public.TCG_User_Relationship RELATIONSHIP
		SET
              follower_user_id = T_RELATIONSHIP.follower_user_id
            , following_user_id = T_RELATIONSHIP.following_user_id
            , is_following = T_RELATIONSHIP.is_following
            , is_blocked = T_RELATIONSHIP.is_blocked
		    , active = T_RELATIONSHIP.active
			, updated_last_on = v_time_start
			, updated_last_by_user_id = v_user_id
		    , change_set_id = v_change_set_id
		FROM Temp_User_Relationship_Save_User_Relationship T_RELATIONSHIP
		WHERE
				RELATIONSHIP.relationship_id = T_RELATIONSHIP.relationship_id
			AND NOT T_RELATIONSHIP.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
			  v_guid
			, T_ERROR.error_type_id
			, T_ERROR.message
			, T_ERROR.temp_id
			, v_time_start
			, v_user_id
			, v_time_start
			, v_user_id
			, v_change_set_id
		FROM Temp_User_Relationship_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_User_Relationship_Save_Error T_ERROR
		WHERE T_ERROR.error_type_id <> v_warning_error_type_id
		LIMIT 1
	);
	
	DELETE FROM tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T WHERE RELATIONSHIP_T.guid = v_guid;

	DROP TABLE IF EXISTS Temp_User_Relationship_Save_User;
	DROP TABLE IF EXISTS Temp_User_Relationship_Save_User_Relationship;
	DROP TABLE IF EXISTS Temp_User_Relationship_Save_Error;
END;
$$;



-- Call it with:
DO $$
DECLARE
	v_comment TEXT := 'User Relationship Save.';
	v_guid UUID;
    v_user_id INT := 3;
    v_success BOOLEAN;
BEGIN
	v_guid := gen_random_uuid();

	INSERT INTO tcg.public.TCG_User_Relationship_Temp (
		  guid
        , relationship_id
        , follower_user_id
        , following_user_id
        , is_following
        , is_blocked
        , active
	)
	VALUES
          (
              v_guid
            , NULL -- relationship_id
            , 3 -- follower_user_id
            , 4 -- following_user_id
            , TRUE -- is_following
            , FALSE -- is_blocked
            , TRUE -- active
        )
        , (
              v_guid
            , NULL -- relationship_id
            , 3 -- follower_user_id
            , 5 -- following_user_id
            , FALSE -- is_following
            , TRUE -- is_blocked
            , TRUE -- active
        )
        , (
              v_guid
            , NULL -- relationship_id
            , 4 -- follower_user_id
            , 3 -- following_user_id
            , TRUE -- is_following
            , FALSE -- is_blocked
            , TRUE -- active
        )
    ;

    CALL tcg.public.USP_TCG_User_Relationship_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 *
FROM tcg.public.TCG_MTG_Game
;
*/

SELECT *
-- DELETE
FROM tcg.public.TCG_User_Relationship_Temp RELATIONSHIP_T
;
SELECT *
-- DELETE
FROM tcg.public.TCG_User_Relationship RELATIONSHIP
;


