# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-02-09 19:30
from __future__ import unicode_literals

from django.db import migrations

SQL_1 = '''
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, lower(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, lower(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();
'''

SQL_2 = '''
CREATE OR REPLACE FUNCTION process_agg_variants() RETURNS TRIGGER AS $pcart_agg_variants$
    DECLARE tagset varchar[];
    DECLARE product_tagset varchar[];
    DECLARE variants_tagset varchar[];
    BEGIN
        -- We need the similar behaviour both for INSERT and UPDATE.
        IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
            -- Build an array of tags of all variants.
            tagset := (SELECT ARRAY(
                SELECT
                    concat(ptp.tag_prefix::text, ':'::text, lower(json_data.value)::text)
                FROM
                    pcart_catalog_productvariant AS v,
                    jsonb_each_text(v.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.product_id)
                WHERE v.id = NEW.id));

            -- Build an array of tags for parent product (for common properties).
            product_tagset := (SELECT ARRAY(
                SELECT
                    concat(ptp.tag_prefix::text, ':'::text, lower(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.product_id)
                WHERE p.id = NEW.product_id));

            -- Setup tags for variant. The next operator is necessary for prevent a recursion.
            IF (NEW.tags <> tagset) THEN
                UPDATE pcart_catalog_productvariant SET tags = tagset WHERE id = NEW.id;
            END IF;

            -- Update tags for parent product.
            variants_tagset := (
                SELECT ARRAY(
                    SELECT DISTINCT unnest(v.tags) AS tag
                    FROM pcart_catalog_productvariant AS v
                    WHERE v.product_id = NEW.product_id));

            -- Merge two sets of tags
            UPDATE pcart_catalog_product
            SET tags = (SELECT ARRAY(SELECT DISTINCT unnest(product_tagset || variants_tagset)))
            WHERE id = NEW.product_id;

            -- Update variants count, min/max variant prices.
            UPDATE pcart_catalog_product SET
                (variants_count, min_variant_price, max_variant_price) =
			(SELECT COUNT(*), MIN(v.price), MAX(v.price)
			    FROM pcart_catalog_productvariant AS v WHERE v.product_id = NEW.product_id)
		    WHERE id = NEW.product_id;
            RETURN NEW;
        ELSIF (TG_OP = 'DELETE') THEN
            -- Build an array of tags of all variants.
            tagset := (SELECT ARRAY(
                SELECT
                    concat(ptp.tag_prefix::text, ':'::text, lower(json_data.value)::text)
                FROM
                    pcart_catalog_productvariant AS v,
                    jsonb_each_text(v.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 = OLD.product_id)
                WHERE v.id = OLD.id));

            -- Build an array of tags for parent product (for common properties).
            product_tagset := (SELECT ARRAY(
                SELECT
                    concat(ptp.tag_prefix::text, ':'::text, lower(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 = OLD.product_id)
                WHERE p.id = OLD.product_id));

            -- Update tags for parent product.
            variants_tagset := (
                SELECT ARRAY(
                    SELECT DISTINCT unnest(v.tags) AS tag
                    FROM pcart_catalog_productvariant AS v
                    WHERE v.product_id = OLD.product_id));

            -- Merge two sets of tags
            UPDATE pcart_catalog_product
            SET tags = (SELECT ARRAY(SELECT DISTINCT unnest(product_tagset || variants_tagset)))
            WHERE id = OLD.product_id;

            -- Update variants count, min/max variant prices.
            UPDATE pcart_catalog_product SET
                (variants_count, min_variant_price, max_variant_price) =
			(SELECT COUNT(*), COALESCE(MIN(v.price), 0), COALESCE(MAX(v.price), 0)
			    FROM pcart_catalog_productvariant AS v WHERE v.product_id = OLD.product_id)
		    WHERE id = OLD.product_id;
		    RETURN OLD;
        END IF;
        RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
$pcart_agg_variants$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS pcart_agg_variants ON pcart_catalog_productvariant;
CREATE TRIGGER pcart_agg_variants
AFTER INSERT OR UPDATE OR DELETE ON pcart_catalog_productvariant
    FOR EACH ROW EXECUTE PROCEDURE process_agg_variants();
'''


class Migration(migrations.Migration):

    dependencies = [
        ('pcart_catalog', '0001_initial'),
    ]

    operations = [
        migrations.RunSQL(SQL_1),
        migrations.RunSQL(SQL_2),
    ]
