CREATE OR REPLACE FUNCTION process_commit_product() RETURNS TRIGGER AS $pcart_commit_product$
    DECLARE tagset varchar[];
    DECLARE variants_tagset varchar[];
    DECLARE merged_tagset varchar[];
    DECLARE max_status_id uuid;
    BEGIN
        -- Build a set of tags for product without variants.
        IF (NEW.variants_count = 0) THEN
            tagset := (SELECT ARRAY(
                SELECT
                    concat(ptp.tag_prefix::text, ':'::text, json_data.value::text)
                FROM
                    pcart_catalog_product AS p,
                    jsonb_each_text(p.properties) AS json_data
                INNER JOIN pcart_catalog_producttypeproperty AS ptp ON
                    json_data.key = ptp.title AND
                    json_data.value <> '' AND
                    ptp.tag_prefix <> '' AND
                    ptp.product_type_id = (SELECT t.product_type_id FROM pcart_catalog_product AS t WHERE t.id = NEW.id)
                WHERE p.id = NEW.id));

            -- Update tags for itself.
            IF (NEW.tags <> tagset) THEN
                UPDATE pcart_catalog_product
                SET tags = tagset
                WHERE id = NEW.id;
            END IF;

            -- Update price
            IF (NEW.price <> NEW.min_variant_price OR NEW.price <> NEW.max_variant_price) THEN
                UPDATE pcart_catalog_product
                SET min_variant_price = NEW.price, max_variant_price = NEW.price
                WHERE id = NEW.id;
            END IF;
            RETURN NEW;
        ELSE
            tagset := (SELECT ARRAY(
                SELECT
                    concat(ptp.tag_prefix::text, ':'::text, json_data.value::text)
                FROM
                    pcart_catalog_product AS p,
                    jsonb_each_text(p.properties) AS json_data
                INNER JOIN pcart_catalog_producttypeproperty AS ptp ON
                    json_data.key = ptp.title AND
                    json_data.value <> '' AND
                    ptp.tag_prefix <> '' AND
                    ptp.product_type_id = (SELECT t.product_type_id FROM pcart_catalog_product AS t WHERE t.id = NEW.id)
                WHERE p.id = NEW.id));

            variants_tagset := (
                SELECT ARRAY(
                    SELECT DISTINCT unnest(v.tags) AS tag
                    FROM pcart_catalog_productvariant AS v
                    WHERE v.product_id = NEW.id));

            -- Merge two sets of tags
            merged_tagset := (SELECT ARRAY(SELECT DISTINCT unnest(tagset || variants_tagset)));

            IF (NEW.tags <> merged_tagset) THEN
                UPDATE pcart_catalog_product
                SET tags = merged_tagset
                WHERE id = NEW.id;
            END IF;

            -- Set status as maximum for all its variants.
            max_status_id := (SELECT id FROM pcart_catalog_productstatus WHERE weight = (
                SELECT max(status.weight)
                FROM pcart_catalog_productvariant AS v
                INNER JOIN pcart_catalog_productstatus AS status ON v.status_id = status.id
                WHERE v.product_id = NEW.id));
            IF (NEW.status_id <> max_status_id) THEN
                UPDATE pcart_catalog_product
                SET status_id = max_status_id
                WHERE id = NEW.id;
            END IF;
            RETURN NEW;
        END IF;
        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
$pcart_commit_product$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS pcart_commit_product ON pcart_catalog_product;
CREATE TRIGGER pcart_commit_product
AFTER INSERT OR UPDATE ON pcart_catalog_product
    FOR EACH ROW EXECUTE PROCEDURE process_commit_product();
