CREATE OR REPLACE PROCEDURE APS.sp_CreateRecipeHistory(
    "RecipeID" uuid,
    "StatusTo" INTEGER,
    "IsNew" BOOLEAN,
    "User" uuid = NULL,
    "Storage" uuid = NULL,
    "Post" uuid = NULL,
    "ProcessName" CHARACTER VARYING DEFAULT NULL::CHARACTER VARYING,
    "StatusInvoice" INTEGER DEFAULT NULL::INTEGER
) AS
$$
DECLARE
    v_ErrorDescription TEXT;
    v_IsValid          BOOLEAN;
    v_Num              INTEGER;
    v_Performed        BOOLEAN;
    v_Loaded           BOOLEAN;
    v_Cancel           BOOLEAN;
    v_NewStatusID      UUID := gen_random_uuid();
    p_DateTime         TIMESTAMP = NULL;

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 = "RecipeID"
      AND "StatusInvoice" IS NULL;

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

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

    INSERT INTO t_status_validation (StatusFrom, StatusTo, valid, error)
    VALUES
        -- 0:Загружен
        (0, 0, "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, "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,
        sv.Error,
        CASE
            WHEN sv.Valid IS NOT NULL THEN sv.Valid
            WHEN sv.StatusFrom = 3 AND sv.StatusTo = 4 AND "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) is null
                THEN true
            END
    INTO
        v_Num,
        v_ErrorDescription,
        v_IsValid
    FROM APS.T_RECIPE r
    JOIN t_status_validation sv ON sv.StatusFrom = r.Status
        AND sv.StatusTo = "StatusTo"
    WHERE
        r.RecipeID = "RecipeID"
        FOR UPDATE OF r;

    IF v_IsValid = 0 THEN
        RAISE EXCEPTION '%', v_ErrorDescription;
        RETURN;
    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,
                                     OrderNumber,
                                     USers,
                                     Storage,
                                     ProcessName)
    SELECT
        v_NewStatusID,
        "RecipeID",
        p_DateTime,
        CASE
            WHEN "StatusTo" = 0 THEN 'Загружен'
            WHEN "StatusTo" = 1 THEN 'Обработан'
            WHEN "StatusTo" = 2 THEN 'На обслуживании'
            WHEN "StatusTo" = 3 THEN 'Отбракован'
            WHEN "StatusTo" = 4 THEN 'Не обработан'
            WHEN "StatusTo" = 5 THEN 'Отложен'
            ELSE 'Неизвестный индекс'
            END,
        "StatusTo",
        v_Num,
        "User",
        "Storage",
        "ProcessName";

    UPDATE APS.T_RECIPE r
    SET
        HCounter = v_Num,
        Status   = "StatusTo",
        Post     = "Post",
        LastStatusHistory = v_NewStatusID
    WHERE
        r.RecipeId = "RecipeID";

END;
$$ LANGUAGE plpgsql;