
 
DROP PROCEDURE IF EXISTS p_dog_save_user;


DELIMITER //
CREATE PROCEDURE p_dog_save_user (
    IN a_comment VARCHAR(500),
	IN a_guid BINARY(36),
    IN a_id_user INT,
    IN a_debug BIT
)
BEGIN
	DECLARE v_code_type_error_bad_data VARCHAR(100);
    DECLARE v_id_type_error_bad_data INT;
    DECLARE v_id_permission_product INT;
    DECLARE v_id_permission_user_edit INT;
    DECLARE v_id_change_set INT;
    DECLARE v_id_access_level_edit INT;
    DECLARE v_is_super_user BIT;
    DECLARE v_can_edit_user BIT;
    DECLARE v_priority_access_level_none INT;
    DECLARE v_priority_access_level_user INT;
    DECLARE v_time_start TIMESTAMP(6);
    
    DECLARE exit handler for SQLEXCEPTION
    BEGIN
        GET DIAGNOSTICS CONDITION 1
            @sqlstate = RETURNED_SQLSTATE
            , @errno = MYSQL_ERRNO
            , @text = MESSAGE_TEXT
		;
        
        ROLLBACK;
        
		CREATE TEMPORARY TABLE IF NOT EXISTS tmp_Msg_Error (
			display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT
			, id_type INT
			, code VARCHAR(250) NOT NULL
			, msg TEXT NOT NULL
		);
        INSERT INTO tmp_Msg_Error (
			id_type
            , code
            , msg
		)
        SELECT 
			MET.id_type
            , @errno
            , @text
		FROM demo.CORE_Msg_Error_Type MET
        WHERE MET.code = 'MYSQL_ERROR'
		;
        SELECT *
        FROM tmp_Msg_Error;
		DROP TABLE IF EXISTS tmp_Msg_Error;
    END;
    
    SET v_time_start := CURRENT_TIMESTAMP(6);
    SET v_code_type_error_bad_data := 'BAD_DATA';
    SET v_id_type_error_bad_data := (SELECT ERROR_TYPE.id_type FROM demo.CORE_Msg_Error_Type ERROR_TYPE WHERE ERROR_TYPE.code = v_code_type_error_bad_data LIMIT 1);
    SET v_id_access_level_edit := (SELECT ACCESS_LEVEL.id_access_level FROM demo.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'EDIT' LIMIT 1);
    SET v_id_permission_user_edit := (SELECT GROUP_CONCAT(PERMISSION.id_permission SEPARATOR ',') FROM demo.DOG_Permission PERMISSION WHERE PERMISSION.code = 'USER_CREATE' LIMIT 1);
    SET v_priority_access_level_none := (SELECT ACCESS_LEVEL.priority FROM demo.DOG_Access_Level ACCESS_LEVEL WHERE ACCESS_LEVEL.code = 'NONE' LIMIT 1);
    
    CALL demo.p_core_validate_guid ( a_guid );
    
    DROP TABLE IF EXISTS tmp_Msg_Error;
    DROP TABLE IF EXISTS tmp_User_Save_User;
    
    CREATE TABLE tmp_User_Save_User (
		id_user INT NOT NULL
        , id_role INT
        , id_role_previous INT
        , id_user_auth0 VARCHAR(250)
        , firstname VARCHAR(250)
        , surname VARCHAR(250)
        , email VARCHAR(254)
        , is_email_verified BIT
        , is_super_user BIT
        , active BIT
        , name_error VARCHAR(1000)
    );
    
    CREATE TABLE tmp_Msg_Error (
		display_order INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
		id_type INT NOT NULL,
        code VARCHAR(250) NOT NULL,
		msg TEXT NOT NULL
    );
    
    -- Get data from Temp table
    INSERT INTO tmp_User_Save_User (
		id_user
        , id_user_auth0
        , id_role
        , firstname
        , surname
        , email
        , is_email_verified
        , is_super_user
        , active
	)
    SELECT 
        USER_T.id_user
        , USER_T.id_user_auth0
        , USER_T.id_role
        , IFNULL(USER_T.firstname, USER.firstname) AS firstname
        , IFNULL(USER_T.surname, USER.surname) AS surname
        , IFNULL(USER_T.email, USER.email) AS email
        , IFNULL(USER_T.is_email_verified, USER.is_email_verified) AS is_email_verified
        , IFNULL(USER_T.is_super_user, USER.is_super_user) AS is_super_user
        , COALESCE(USER_T.active, USER.active, 1) AS active
	FROM demo.DOG_User_Temp USER_T
    LEFT JOIN demo.DOG_User USER ON USER_T.id_user = USER.id_user
    WHERE USER_T.guid = a_guid
    ;

    UPDATE tmp_User_Save_User t_USER
    SET 
        t_USER.name_error = IFNULL(t_USER.email, t_USER.id_user_auth0)
    ;
    
    -- Validation
    -- Missing mandatory fields
    -- role
    IF EXISTS (
        SELECT * 
        FROM tmp_User_Save_User t_USER
        LEFT JOIN demo.DOG_Role ROLES ON t_USER.id_role = ROLES.id_role
        WHERE 
                ISNULL(t_USER.id_role) 
            OR  ISNULL(ROLES.id_role)
        LIMIT 1
    ) THEN
		INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		SELECT
			v_id_type_error_bad_data
			, v_code_type_error_bad_data
			, CONCAT('The following User(s) do not have a role: ', GROUP_CONCAT(t_USER.name_error SEPARATOR ', ')) AS msg
		FROM tmp_User_Save_User t_USER
        LEFT JOIN demo.DOG_Role ROLES ON t_USER.id_role = ROLES.id_role
        WHERE 
                ISNULL(t_USER.id_role) 
            OR  ISNULL(ROLES.id_role)
		;
    END IF;
    -- email
    IF EXISTS (SELECT * FROM tmp_User_Save_User t_USER WHERE ISNULL(t_USER.email) LIMIT 1) THEN
		INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		SELECT
			v_id_type_error_bad_data
			, v_code_type_error_bad_data
			, CONCAT('The following User(s) do not have an email: ', GROUP_CONCAT(t_USER.name_error SEPARATOR ', ')) AS msg
		FROM tmp_User_Save_User t_USER
		WHERE ISNULL(t_USER.email)
		;
    END IF;
    -- is_super_user
    IF EXISTS (SELECT * FROM tmp_User_Save_User t_USER WHERE ISNULL(t_USER.is_super_user) LIMIT 1) THEN
		INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		SELECT
			v_id_type_error_bad_data
			, v_code_type_error_bad_data
			, CONCAT('The following User(s) do not have an is super user field: ', GROUP_CONCAT(t_USER.name_error SEPARATOR ', ')) AS msg
		FROM tmp_User_Save_User t_USER
		WHERE ISNULL(t_USER.is_super_user)
		;
    END IF;
    -- is_email_verified
    IF EXISTS (SELECT * FROM tmp_User_Save_User t_USER WHERE ISNULL(t_USER.is_email_verified) LIMIT 1) THEN
		INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		SELECT
			v_id_type_error_bad_data
			, v_code_type_error_bad_data
			, CONCAT('The following User(s) do not have an is email verified: ', GROUP_CONCAT(t_USER.name_error SEPARATOR ', ')) AS msg
		FROM tmp_User_Save_User t_USER
		WHERE ISNULL(t_USER.is_email_verified)
		;
    END IF;
    
    -- Get old role
    UPDATE tmp_User_Save_User t_USER
    INNER JOIN demo.DOG_User_Role_Link USER_ROLE_LINK 
        ON  t_USER.id_user = USER_ROLE_LINK.id_user
        AND USER_ROLE_LINK.active = 1
    INNER JOIN demo.DOG_Role ROLES 
        ON  USER_ROLE_LINK.id_role = ROLES.id_role
        AND ROLES.active = 1
    SET t_USER.id_role_previous = USER_ROLE_LINK.id_role
    WHERE t_USER.id_user > 0
    ;
    
    -- Permissions
    IF a_debug = 1 THEN
		SELECT 
			  a_guid -- a_guid
            , 0 -- get_all_user
            , 0 -- get_inactive_user
            , a_id_user -- ids_user
            , '' -- a_auth0_ids_user
            , '' -- a_names_user
            , '' -- a_emails_user
            , 1 -- a_require_all_id_search_filters_met
            , 1 -- a_require_any_id_search_filters_met
            , 0 -- a_require_all_non_id_search_filters_met
            , 0 -- a_require_any_non_id_search_filters_met
            , v_id_permission_user_edit -- ids_permission
            , v_id_access_level_edit -- ids_access_level
            , 0 -- a_show_errors
			, 0 -- a_debug
        ;
    END IF;
    
	CALL demo.p_dog_calc_user_access(
          a_guid -- a_guid
        , 0 -- get_all_user
        , 0 -- get_inactive_user
        , a_id_user -- ids_user
        , '' -- a_auth0_ids_user
        , '' -- a_names_user
        , '' -- a_emails_user
        , 1 -- a_require_all_id_search_filters_met
        , 1 -- a_require_any_id_search_filters_met
        , 0 -- a_require_all_non_id_search_filters_met
        , 0 -- a_require_any_non_id_search_filters_met
        , v_id_permission_user_edit -- ids_permission
        , v_id_access_level_edit -- ids_access_level
        , 0 -- a_show_errors
        , 0 -- a_debug
    );
    
    SELECT 
        CASE WHEN IFNULL(CALC_USER_T.can_edit, 0) = 1 THEN 1 ELSE 0 END AS can_edit
        , IFNULL(CALC_USER_T.is_super_user, 0) AS is_super_user
        , IFNULL(CALC_USER_T.priority_access_level_user, v_priority_access_level_none) AS priority_access_level
    INTO
        v_can_edit_user
        , v_is_super_user
        , v_priority_access_level_user
    FROM demo.DOG_Calc_User_Access_Temp CALC_USER_T 
    WHERE
            CALC_USER_T.GUID = a_guid
        AND CALC_USER_T.id_user = a_id_user
        AND CALC_USER_T.id_permission_required = v_id_permission_user_edit
    ;

    IF (
            v_is_super_user = 0
        AND EXISTS (
            WITH User_Company AS (
                SELECT USER_COMPANY_LINK.id_company
                FROM demo.DOG_User_Company_Link USER_COMPANY_LINK
                WHERE USER_COMPANY_LINK.id_user = a_id_user
            )
            SELECT * 
            FROM tmp_User_Save_User t_USER
            LEFT JOIN User_Company USER_COMPANY ON t_USER.id_company = USER_COMPANY.id_company
            WHERE USER_COMPANY.id_company IS NULL
        )
    ) THEN
        DELETE FROM tmp_Msg_Error;
        INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		VALUES (
			v_id_type_error_no_permission
			, v_code_type_error_no_permission
			, 'You do not have permission to edit User(s) in other Company(s).'
        )
        ;
    END IF;

    IF (
            v_is_super_user = 0
        AND v_priority_access_level_user > v_priority_access_level_admin
        AND EXISTS (
            SELECT * 
            FROM tmp_User_Save_User t_USER
            WHERE t_USER.id_user <> a_id_user
        )
    ) THEN
        DELETE FROM tmp_Msg_Error;
        INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		VALUES (
			v_id_type_error_no_permission
			, v_code_type_error_no_permission
			, 'You do not have permission to edit other Users.'
        )
        ;
    END IF;
    
    -- Attempt to change role they can't access
    -- role from
    IF EXISTS (
        SELECT * 
        FROM tmp_User_Save_User t_USER
        INNER JOIN demo.DOG_User USER ON t_USER.id_user = USER.id_user
        INNER JOIN demo.DOG_User_Role_Link USER_ROLE_LINK ON t_USER.id_user = USER_ROLE_LINK.id_user
        INNER JOIN demo.DOG_Role ROLES ON USER_ROLE_LINK.id_role = ROLES.id_role
        INNER JOIN demo.DOG_Access_Level ACCESS_LEVEL ON ROLES.id_access_level_required = ACCESS_LEVEL.id_access_level
        WHERE ACCESS_LEVEL.priority < v_priority_access_level_user
        LIMIT 1
    ) THEN
		INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		SELECT
			v_id_type_error_bad_data
			, v_code_type_error_bad_data
			, CONCAT('The following User(s) have role(s) you cannot access: ', GROUP_CONCAT(t_USER.name_error SEPARATOR ', ')) AS msg
		FROM tmp_User_Save_User t_USER
        INNER JOIN demo.DOG_User USER ON t_USER.id_user = USER.id_user
        INNER JOIN demo.DOG_User_Role_Link USER_ROLE_LINK ON t_USER.id_user = USER_ROLE_LINK.id_user
        INNER JOIN demo.DOG_Role ROLES ON USER_ROLE_LINK.id_role = ROLES.id_role
        INNER JOIN demo.DOG_Access_Level ACCESS_LEVEL ON ROLES.id_access_level_required = ACCESS_LEVEL.id_access_level
        WHERE ACCESS_LEVEL.priority < v_priority_access_level_user
		;
    END IF;
    -- role to
    IF EXISTS (
        SELECT * 
        FROM tmp_User_Save_User t_USER
        INNER JOIN demo.DOG_Role ROLES ON t_USER.id_role = ROLES.id_role
        INNER JOIN demo.DOG_Access_Level ACCESS_LEVEL ON ROLES.id_access_level_required = ACCESS_LEVEL.id_access_level
        WHERE ACCESS_LEVEL.priority < v_priority_access_level_user
        LIMIT 1
    ) THEN
		INSERT INTO tmp_Msg_Error (
			id_type
			, code
			, msg
		)
		SELECT
			v_id_type_error_bad_data
			, v_code_type_error_bad_data
			, CONCAT('The following User(s) have role(s) you cannot access: ', GROUP_CONCAT(t_USER.name_error SEPARATOR ', ')) AS msg
		FROM tmp_User_Save_User t_USER
        INNER JOIN demo.DOG_Role ROLES ON t_USER.id_role = ROLES.id_role
        INNER JOIN demo.DOG_Access_Level ACCESS_LEVEL ON ROLES.id_access_level_required = ACCESS_LEVEL.id_access_level
        WHERE ACCESS_LEVEL.priority < v_priority_access_level_user
		;
    END IF;
    
    CALL demo.p_dog_clear_calc_user_access( a_guid, 0 );

    
    IF NOT EXISTS (SELECT * FROM tmp_Msg_Error LIMIT 1) THEN
		START TRANSACTION;
        
            INSERT INTO demo.DOG_User_Change_Set ( comment )
            VALUES ( a_comment )
            ;
            
            SET v_id_change_set := LAST_INSERT_ID();
            
            UPDATE demo.DOG_User USER
            INNER JOIN tmp_User_Save_User t_USER ON USER.id_user = t_USER.id_user
            SET 
                USER.id_user_auth0 = t_USER.id_user_auth0
                , USER.firstname = t_USER.firstname
                , USER.surname = t_USER.surname
                , USER.email = t_USER.email
                , USER.is_email_verified = t_USER.is_email_verified
                , USER.is_super_user = t_USER.is_super_user
                , USER.active = t_USER.active
                , USER.id_change_set = v_id_change_set
            ;

            IF EXISTS (
                SELECT * 
                FROM tmp_User_Save_User t_USER 
                WHERE 
                        t_USER.id_role IS NOT NULL
                    AND t_USER.id_role_previous IS NULL
                LIMIT 1
            ) THEN
                INSERT INTO demo.DOG_User_Role_Link (
                    id_user
                    , id_role
                    , active
                    , id_user_created_by
                )
                SELECT
                    t_USER.id_user
                    , t_USER.id_role
                    , t_USER.active
                    , a_id_user AS id_user_created_by
                FROM tmp_User_Save_User t_USER 
                WHERE 
                        t_USER.id_role IS NOT NULL
                    AND t_USER.id_role_previous IS NULL
                ;
            END IF;

            IF EXISTS (SELECT * FROM tmp_User_Save_User t_USER WHERE t_USER.id_role <> t_USER.id_role_previous LIMIT 1) THEN
                UPDATE demo.DOG_User_Role_Link USER_ROLE_LINK
                INNER JOIN tmp_User_Save_User t_USER ON USER_ROLE_LINK.id_user = t_USER.id_user
                SET 
                      USER_ROLE_LINK.id_role = t_USER.id_role
                    , USER_ROLE_LINK.id_change_set = v_id_change_set
                ;
            END IF;
            
		COMMIT;
    END IF;
    
    START TRANSACTION;
		
		DELETE FROM demo.DOG_User_Temp
		WHERE GUID = a_guid;
		
	COMMIT;
	
    # Errors
    SELECT *
    FROM tmp_Msg_Error t_ME
	INNER JOIN demo.CORE_Msg_Error_Type MET ON t_ME.id_type = MET.id_type
	;
    
	IF a_debug = 1 THEN
		SELECT * from tmp_User_Save_User;
	END IF;

    DROP TABLE IF EXISTS tmp_Msg_Error;
    DROP TABLE IF EXISTS tmp_User_Save_User;
    
	IF a_debug = 1 THEN
		CALL demo.p_debug_timing_reporting ( v_time_start );
	END IF;
END //
DELIMITER ;



CALL demo.p_dog_clear_calc_user_access( 
    'greensgreensgreensgreensgreensgreens' -- guid
    , 0 -- debug 
);
	CALL demo.p_dog_calc_user_access(
          'greensgreensgreensgreensgreensgreens' -- a_guid
        , 0 -- get_all_user
        , 0 -- get_inactive_user
        , 1 -- ids_user
        , '' -- a_auth0_ids_user
        , '' -- a_names_user
        , '' -- a_emails_user
        , 1 -- a_require_all_id_search_filters_met
        , 1 -- a_require_any_id_search_filters_met
        , 0 -- a_require_all_non_id_search_filters_met
        , 0 -- a_require_any_non_id_search_filters_met
        , 15 -- ids_permission
        , 2 -- ids_access_level
        , 0 -- a_show_errors
        , 0 -- a_debug
    );
    SELECT * FROM demo.DOG_Calc_User_Access_Temp;
CALL demo.p_dog_clear_calc_user_access( 
    'greensgreensgreensgreensgreensgreens' -- guid
    , 0 -- debug 
);
    SELECT * FROM demo.DOG_Calc_User_Access_Temp;

CALL demo.p_dog_save_user (
	'Test' -- comment
    , 'greensgreensgreensgreensgreensgreens' -- guid
    , 1 -- id_user
    , 1 -- debug
);

CALL demo.p_dog_clear_calc_user_access( 
    'greensgreensgreensgreensgreensgreens' -- guid
    , 0 -- debug 
);
