-- Item style related queries
--
-- Entities:
--
--: StyleRow(external_id?, created_by?, core?, country_of_origin?, tariff_no?)
--: NestedStyleRow(external_id?, created_by?, core?, country_of_origin?, tariff_no?, is_new?)
--: NestedStyleSummaryRow()
--: StyleRefs(external_id?)
--
--
-- Queries:
--
--! select_styles (ids?) : StyleRow
SELECT
    style.*,
    coalesce(joined_categories.json_data, '[]') AS "categories",
    coalesce(joined_attributes.json_data, '[]') AS "attributes"
FROM
    style
LEFT JOIN (
    SELECT
        style_attribute.style_id,
        json_agg(
            json_build_object(
                'id',
                "attribute".id,
                'title',
                "attribute".title,
                'description',
                "attribute".description,
                'slug',
                "attribute".slug,
                'external_id',
                "attribute".external_id,
                'type',
                json_build_object(
                    'id',
                    attributetype.id,
                    'name',
                    attributetype.name,
                    'slug',
                    attributetype.slug,
                    'external_id',
                    attributetype.external_id
                )
            )
            ORDER BY
                attributetype.name,
                "attribute".title
        ) FILTER (
            WHERE
            "attribute".id IS NOT NULL
        ) AS json_data
    FROM
        attribute
    INNER JOIN attributetype ON attributetype.id = "attribute".type_id
    INNER JOIN style_attribute ON "attribute".id = style_attribute.attribute_id
    WHERE
        "attribute".organization_id = :organization_id
    GROUP BY
        style_attribute.style_id
    ) AS joined_attributes ON joined_attributes.style_id = style.id
LEFT JOIN (
    SELECT
        style_category.style_id,
        json_agg(category.*) FILTER (
            WHERE
            category.id IS NOT NULL
        ) AS "json_data"
    FROM
        category
    INNER JOIN style_category ON category.id = style_category.category_id
    WHERE
        category.organization_id = :organization_id
    GROUP BY
        style_category.style_id
    ) AS joined_categories ON joined_categories.style_id = style.id
WHERE
    style.organization_id = :organization_id
    AND :ids::int[] IS NULL OR style.id = any(:ids)
ORDER BY
    style.number;

--! select_collection_styles_nested (ids?, pricelist_ids_to_display?, statuses?) : NestedStyleRow
WITH new_styles AS (
    SELECT
        new_collection_style.style_id,
        new_collection_style.is_new
    FROM
        new_collection_style
    WHERE
        new_collection_style.collection_id = :collection_id
),

new_colors AS (
    SELECT
        new_collection_color.color_id,
        new_collection_color.is_new
    FROM
        new_collection_color
    WHERE
        new_collection_color.collection_id = :collection_id
)

SELECT
    style.*,
    new_styles.is_new,
    coalesce(joined_colors.json_data, '[]') AS "colors",
    coalesce(joined_prices.json_data, '[]') AS "prices",
    coalesce(joined_attributes.json_data, '[]') AS "attributes",
    coalesce(joined_categories.json_data, '[]') AS "categories"
FROM
    style
LEFT JOIN new_styles ON new_styles.style_id = style.id
INNER JOIN (
        SELECT
            color.style_id,
            json_agg(
                json_build_object(
                    'id',
                    color.id,
                    'number',
                    color.number,
                    'name',
                    color.name,
                    'slug',
                    color.slug,
                    'external_id',
                    color.external_id,
                    'sizes', coalesce(joined_sizes.json_data, '[]'),
                    'images', coalesce(joined_images.json_data, '[]'),
                    'is_new',
                    new_colors.is_new
                )
                ORDER BY
                    color.number
            ) FILTER (
                WHERE
                color.id IS NOT NULL
            ) AS json_data
        FROM
            color
        LEFT JOIN new_colors ON new_colors.color_id = color.id
        INNER JOIN (
            SELECT
                size.color_id,
                json_agg(
                    json_build_object(
                        'id',
                        size.id,
                        'number',
                        size.number,
                        'position',
                        size.position,
                        'name',
                        size.name,
                        'service_item',
                        size.service_item,
                        'delivery_period',
                        size.delivery_period,
                        'ean_code',
                        size.ean_code,
                        'status',
                        size.status,
                        'slug',
                        size.slug,
                        'external_id',
                        size.external_id
                    )
                    ORDER BY
                        size.number
                ) FILTER (
                    WHERE
                    size.id IS NOT NULL
                ) AS json_data
            FROM
                size
            INNER JOIN color ON size.color_id = color.id
            INNER JOIN style ON color.style_id = style.id
            INNER JOIN size_collection ON size_collection.size_id = size.id
            WHERE
                size.organization_id = :organization_id
                AND size_collection.collection_id = :collection_id
                AND (
                    :statuses::text[] IS NULL OR size.status = any(:statuses)
                )
            GROUP BY
                size.color_id
            ) AS joined_sizes ON joined_sizes.color_id = color.id
        LEFT JOIN (
            SELECT
                image.color_id,
                json_agg(
                    json_build_object(
                        'id',
                        image.id,
                        'url',
                        image.url,
                        'external_id',
                        image.external_id
                    )
                    ORDER BY
                        image.position ASC,
                        image.uploaded_at DESC
                ) AS json_data
            FROM
                image
            WHERE
                image.organization_id = :organization_id
            GROUP BY
                image.color_id
            ) AS joined_images ON joined_images.color_id = color.id
        WHERE
            color.organization_id = :organization_id
        GROUP BY
            color.style_id
    ) AS joined_colors ON joined_colors.style_id = style.id
LEFT JOIN (
        SELECT
            price.style_id,
            json_agg(
                json_build_object(
                    'id',
                    price.id,
                    'type',
                    price.type,
                    'uom',
                    price.uom,
                    'currency',
                    price.currency,
                    'amount',
                    price.amount,
                    'start',
                    price.start,
                    'end',
                    price.end,
                    'list',
                    json_build_object(
                        'id',
                        pricelist.id,
                        'slug',
                        pricelist.slug,
                        'external_id',
                        pricelist.external_id,
                        'name',
                        pricelist.name
                    )
                )
                ORDER BY
                    price.type,
                    pricelist.name,
                    price."start"
            ) FILTER (
                WHERE
                price.id IS NOT NULL
            ) AS json_data
        FROM
            price
        INNER JOIN pricelist ON pricelist.id = price.list_id
        INNER JOIN collection_pricelist ON
            collection_pricelist.pricelist_id = pricelist.id
        WHERE
            price.organization_id = :organization_id
            AND (
                :pricelist_ids_to_display::int[] IS NULL
                OR pricelist.id = any(:pricelist_ids_to_display)
            )
            AND collection_pricelist.collection_id = :collection_id
            AND (
                collection_pricelist.price_date
                BETWEEN price."start" AND price."end"
            )
        GROUP BY
            price.style_id
    ) AS joined_prices ON joined_prices.style_id = style.id
LEFT JOIN (
        SELECT
            style_attribute.style_id,
            json_agg(
                json_build_object(
                    'id',
                    "attribute".id,
                    'title',
                    "attribute".title,
                    'description',
                    "attribute".description,
                    'slug',
                    "attribute".slug,
                    'external_id',
                    "attribute".external_id,
                    'type',
                    json_build_object(
                        'id',
                        attributetype.id,
                        'name',
                        attributetype.name,
                        'slug',
                        attributetype.slug,
                        'external_id',
                        attributetype.external_id
                    )
                )
                ORDER BY
                    attributetype.name,
                    "attribute".title
            ) FILTER (
                WHERE
                "attribute".id IS NOT NULL
            ) AS json_data
        FROM
            attribute
        INNER JOIN attributetype ON attributetype.id = "attribute".type_id
        INNER JOIN style_attribute ON "attribute".id = style_attribute.attribute_id
        WHERE
            "attribute".organization_id = :organization_id
        GROUP BY
            style_attribute.style_id
    ) AS joined_attributes ON joined_attributes.style_id = style.id
LEFT JOIN (
        SELECT
            style_category.style_id,
            json_agg(
                json_build_object(
                    'id',
                    category.id,
                    'slug',
                    category.slug,
                    'name',
                    category.name,
                    'external_id',
                    category.external_id
                )
            ) FILTER (
                WHERE
                category.id IS NOT NULL
            ) AS "json_data"
        FROM
            category
        INNER JOIN style_category ON category.id = style_category.category_id
        WHERE
            category.organization_id = :organization_id
        GROUP BY
            style_category.style_id
    ) AS joined_categories ON joined_categories.style_id = style.id
WHERE
    (:ids::int[] IS NULL OR style.id = any(:ids))
ORDER BY
    style.number;

--
--! select_nested_style_summaries (ids?, categories?, attributes?, statuses?) : NestedStyleSummaryRow
WITH attribute_matches AS (
    SELECT styles_matching_attributes(:attributes)
)

SELECT
    style.id,
    style.name,
    style.number,
    coalesce(joined_colors.json_data, '[]') AS "colors"
FROM
    style
INNER JOIN (
        SELECT
            color.style_id,
            json_agg(
                json_build_object(
                    'id',
                    color.id,
                    'number',
                    color.number,
                    'name',
                    color.name,
                    'sizes', coalesce(joined_sizes.json_data, '[]'),
                    'primary_image', primary_image.json_data
                )
                ORDER BY
                    color.number
            ) FILTER (
                WHERE
                color.id IS NOT NULL
            ) AS json_data
        FROM
            color
        INNER JOIN (
            SELECT
                size.color_id,
                json_agg(
                    json_build_object(
                        'id',
                        size.id,
                        'number',
                        size.number,
                        'name',
                        size.name
                    )
                    ORDER BY
                        size.number
                ) FILTER (
                    WHERE
                    size.id IS NOT NULL
                ) AS json_data
            FROM
                size
            INNER JOIN color ON size.color_id = color.id
            WHERE
                size.organization_id = :organization_id
                AND (:statuses::text[] IS NULL OR size.status = any(:statuses))
            GROUP BY
                size.color_id
            ) AS joined_sizes ON joined_sizes.color_id = color.id
        LEFT JOIN (
            -- We utilize distinct here because there might be multiple rows with
            -- `position = 1` for a given `color_id`.
            SELECT DISTINCT ON (image.color_id)
                image.color_id,
                json_build_object(
                    'id',
                    image.id,
                    'url',
                    image.url,
                    'external_id',
                    image.external_id
                ) AS json_data
            FROM
                image
            WHERE
                image.organization_id = :organization_id
                AND image.position = 1
            ) AS primary_image ON primary_image.color_id = color.id
        WHERE
            color.organization_id = :organization_id
        GROUP BY
            color.style_id
    ) AS joined_colors ON joined_colors.style_id = style.id
LEFT JOIN (
    SELECT
        style_category.style_id,
        array_agg(style_category.category_id) AS category_ids
    FROM style_category
    GROUP BY style_category.style_id
) AS style_categories ON style_categories.style_id = style.id
WHERE
    style.organization_id = :organization_id
    AND (:ids::int[] IS NULL OR style.id = any(:ids))
    AND (:categories::int[] IS NULL OR style_categories.category_ids && :categories)
    AND (:attributes::int[] IS NULL OR style.id IN (SELECT * FROM attribute_matches))
ORDER BY
    style.number;

--
--! get_style_id (id?, external_id?, slug?)
SELECT style.id
FROM
    style
WHERE
    style.organization_id = :organization_id
    AND (
        (style.id = coalesce(:id, -1))
        OR (
            style.external_id = coalesce(:external_id, '___NON_EXISTING___')
            OR (style.slug = coalesce(:slug, '___NON_EXISTING___'))
        )
    );

--
-- Get all references for the given id, external_id or slug
--
--! get_style_refs (id?, external_id?, slug?) : StyleRefs
SELECT
    style.id,
    style.external_id,
    style.slug
FROM
    style
WHERE
    style.organization_id = :organization_id
    AND (
        (style.id = coalesce(:id, -1))
        OR (
            style.external_id = coalesce(:external_id, '___NON_EXISTING___')
            OR (style.slug = coalesce(:slug, '___NON_EXISTING___'))
        )
    );

--
--! insert_style (external_id?, core?, country_of_origin?, tariff_no?)
INSERT INTO
style (
    organization_id,
    slug,
    external_id,
    number,
    name,
    description,
    core,
    country_of_origin,
    tariff_no,
    net_weight,
    gross_weight,
    unit_volume,
    created_by
)
VALUES
(
    :organization_id,
    :slug,
    :external_id,
    :number,
    :name,
    :description,
    :core,
    :country_of_origin,
    :tariff_no,
    :net_weight,
    :gross_weight,
    :unit_volume,
    :created_by
)
RETURNING
id;

--
--! update_style (slug?, external_id?, number?, name?, description?, core?, country_of_origin?, tariff_no?, net_weight?, gross_weight?, unit_volume?)
UPDATE
style
SET
    slug = coalesce(:slug, slug),
    external_id = coalesce(:external_id, external_id),
    number = coalesce(:number, number),
    name = coalesce(:name, name),
    description = coalesce(:description, description),
    core = coalesce(:core, core),
    country_of_origin = coalesce(:country_of_origin, country_of_origin),
    tariff_no = coalesce(:tariff_no, tariff_no),
    net_weight = coalesce(:net_weight, net_weight),
    gross_weight = coalesce(:gross_weight, gross_weight),
    unit_volume = coalesce(:unit_volume, unit_volume)
WHERE
    id = :id
RETURNING
id;

--! delete_style
DELETE FROM
style
WHERE
    organization_id = :organization_id
    AND id = :id
RETURNING
id;
