CREATE OR REPLACE PROCEDURE APS.sp_CreateRecipeHistory(
    p_RecipeID uuid,
    p_StatusTo INTEGER,
    p_IsNew BOOLEAN,
    p_DateTime TIMESTAMP = NULL,
    p_User uuid = NULL,
    p_Storage uuid = NULL,
    p_Post uuid = NULL,
    p_ProcessName VARCHAR(255) = NULL,
    p_StatusInvoice INTEGER = NULL
) AS
$$
DECLARE
    v_ErrorDescription TEXT;
    v_IsValid          BOOLEAN;
    v_Num              INTEGER;
    v_Performed        BOOLEAN;
    v_Loaded           BOOLEAN;
    v_Cancel           BOOLEAN;

BEGIN

    CREATE TEMPORARY TABLE t_status_validation
    (
        StatusFrom INTEGER,
        StatusTo   INTEGER,
        Valid      BOOLEAN,
        Error      TEXT
    );

    SELECT
        ss.State,
        CASE WHEN ss.State = 1 THEN 0 ELSE 1 END
    INTO
        v_Performed,
        v_Cancel
    FROM APS.T_RECIPE_INVOICE ri
    JOIN STOR.T_STORAGE_INVOICE ss ON ss.InvoiceID = ri.InvoiceID
    WHERE
          ri.Recipe = p_RecipeID
      AND p_StatusInvoice IS NULL;

    SELECT
        p_StatusInvoice,
        CASE WHEN p_StatusInvoice = 1 THEN 0 ELSE 1 END
    INTO
        v_Performed
    WHERE
        p_StatusInvoice IS NOT NULL;

    v_Performed = COALESCE(v_Performed, 0);
    v_Cancel = COALESCE(v_Cancel, 1);
    v_Loaded = CASE WHEN p_ProcessName = 'RecipeMessageHandlingProcess' THEN 1 ELSE 0 END;

    INSERT INTO t_statusValidation (StatusFrom, StatusTo, valid, error)
    VALUES
        -- 0:Загружен
        (0, 0, p_IsNew, 'Невозможная операция (0:Загружен -> 0:Загружен)'),
        (0, 1, v_Performed, 'Невозможная операция (0:Загружен -> 1:Обработан)'),
        (0, 2, TRUE, 'Невозможная операция (0:Загружен -> 2:Отсрочен)'),
        (0, 3, TRUE, 'Невозможная операция (0:Загружен -> 3:Отбракован)'),
        (0, 4, FALSE, 'Невозможная операция (0:Загружен -> 4:Не обработан)'),
        (0, 5, v_Performed, 'Невозможная операция (0:Загружен -> 5:Отложен)'),
        -- 1:Обработан
        (1, 0, FALSE, 'Невозможная операция (1:Обработан -> 0:Загружен)'),
        (1, 1, FALSE, 'Невозможная операция (1:Обработан -> 1:Обработан)'),
        (1, 2, FALSE, 'Невозможная операция (1:Обработан -> 2:Отсрочен)'),
        (1, 3, FALSE, 'Невозможная операция (1:Обработан -> 3:Отбракован)'),
        (1, 4, v_Cancel, 'Невозможная операция (1:Обработан -> 4:Не обработан)'),
        (1, 5, FALSE, 'Невозможная операция (1:Обработан -> 5:Отложен)'),
        -- 2:Отсрочен
        (2, 0, FALSE, 'Невозможная операция (2:Отсрочен -> 0:Загружен)'),
        (2, 1, v_Performed, 'Невозможная операция (2:Отсрочен -> 1:Обработан)'),
        (2, 2, FALSE, 'Невозможная операция (2:Отсрочен -> 2:Отсрочен)'),
        (2, 3, TRUE, 'Невозможная операция (2:Отсрочен -> 3:Отбракован)'),
        (2, 4, TRUE, 'Невозможная операция (2:Отсрочен -> 4:Не обработан)'),
        (2, 5, v_Performed, 'Невозможная операция (2:Отсрочен -> 5:Отложен)'),
        -- 3:Отбракован
        (3, 0, FALSE, 'Невозможная операция (3:Отбракован -> 0:Загружен)'),
        (3, 1, FALSE, 'Невозможная операция (3:Отбракован -> 1:Обработан)'),
        (3, 2, FALSE, 'Невозможная операция (3:Отбракован -> 2:Отсрочен)'),
        (3, 3, FALSE, 'Невозможная операция (3:Отбракован -> 3:Отбракован)'),
        (3, 4, NULL, 'Невозможная операция (3:Отбракован -> 4:Не обработан)'),
        (3, 5, FALSE, 'Невозможная операция (3:Отбракован -> 5:Отложен)'),
        -- 4:Не обработан
        (4, 0, v_Loaded, 'Невозможная операция (4:Не обработан -> 0:Загружен)'),
        (4, 1, v_Performed, 'Невозможная операция (4:Не обработан -> 1:Обработан)'),
        (4, 2, TRUE, 'Невозможная операция (4:Не обработан -> 2:Отсрочен)'),
        (4, 3, TRUE, 'Невозможная операция (4:Не обработан -> 3:Отбракован)'),
        (4, 4, p_IsNew, 'Невозможная операция (4:Не обработан -> 4:Не обработан)'),
        (4, 5, v_Performed, 'Невозможная операция (4:Не обработан -> 5:Отложен)'),
        -- 5:Отложен
        (5, 0, FALSE, 'Невозможная операция (5:Отложен -> 0:Загружен)'),
        (5, 1, v_Performed, 'Невозможная операция (5:Отложен -> 1:Обработан)'),
        (5, 2, FALSE, 'Невозможная операция (5:Отложен -> 2:Отсрочен)'),
        (5, 3, FALSE, 'Невозможная операция (5:Отложен -> 3:Отбракован)'),
        (5, 4, v_Cancel, 'Невозможная операция (5:Отложен -> 4:Не обработан)'),
        (5, 5, FALSE, 'Невозможная операция (5:Отложен -> 5:Отложен)');

    SELECT
        r.HCounter,
        r.ErrorDescription,
        CASE
            WHEN sv.Valid IS NOT NULL THEN sv.Valid
            WHEN sv.StatusFrom = 3 AND sv.StatusTo = 4 AND p_ProcessName IS NULL AND (SELECT
                                                                                          rch.ProcessName
                                                                                      FROM APS.T_RECIPE_STATUS_HISTORY rch
                                                                                      WHERE
                                                                                          rch.Recipe = r.RecipeID
                                                                                      ORDER BY
                                                                                          rch.OrderNumber DESC
                                                                                      LIMIT 1)
                THEN 1
            END
    INTO
        v_Num,
        v_ErrorDescription,
        v_IsValid
    FROM APS.T_RECIPE r
    JOIN t_statusValidation sv ON sv.StatusFrom = r.Status
        AND sv.StatusTo = p_StatusTo
    WHERE
        r.RecipeID = p_RecipeID
        FOR UPDATE OF r;

    IF v_IsValid = 0 THEN
        RAISE EXCEPTION '%', v_ErrorDescription;
    END IF;

    p_DateTime = COALESCE(p_DateTime, CURRENT_TIMESTAMP);
    v_Num = v_num + 1;

    INSERT INTO
        APS.T_RECIPE_STATUS_HISTORY (RecipeStatusHistoryID,
                                     Recipe,
                                     CreationDateTime,
                                     StatusText,
                                     StatusIndex,
                                     OrderNumbr,
                                     USers,
                                     Storage,
                                     ProcessName)
    SELECT
        gen_random_uuid(),
        p_RecipeID,
        p_DateTime,
        CASE
            WHEN p_StatusTo = 0 THEN 'Загружен'
            WHEN p_StatusTo = 1 THEN 'Обработан'
            WHEN p_StatusTo = 2 THEN 'Отсрочен'
            WHEN p_StatusTo = 3 THEN 'Отбракован'
            WHEN p_StatusTo = 4 THEN 'Не обработан'
            WHEN p_StatusTo = 5 THEN 'Отложен'
            ELSE 'Неизвестный индекс'
            END,
        p_StatusTo,
        v_Num,
        p_User,
        p_Storage,
        p_ProcessName;

    UPDATE APS.T_RECIPE r
    SET
        HCounter = v_Num,
        Status   = p_StatusTo,
        Post     = p_Post
    WHERE
        r.RecipeId = p_RecipeID;

END;
$$ LANGUAGE plpgsql;