<?php

declare(strict_types=1);

namespace App\Shopware;

use App\Commerce\Dto\CommerceSearchQuery;

final class ShopwareCriteriaBuilder
{
    public function build(
        CommerceSearchQuery $query,
        ?int                $limit = 25,
        ?bool               $grouping = false
    ): array
    {
        return $this->buildCriteria(
            query: $query,
            limit: $limit,
            grouping: $grouping,
            includeRichTextFields: true
        );
    }

    /**
     * Builds a smaller Store API criteria payload for retrying Shopware responses
     * that fail while JSON-encoding product descriptions or custom fields.
     */
    public function buildSafe(
        CommerceSearchQuery $query,
        ?int                $limit = 25,
        ?bool               $grouping = false
    ): array
    {
        return $this->buildCriteria(
            query: $query,
            limit: $limit,
            grouping: $grouping,
            includeRichTextFields: true,
            includeMediaFields: false,
            includeSeoUrls: true,
            includeManufacturer: true
        );
    }

    /**
     * Builds the smallest useful Store API payload for UTF-8 recovery.
     * It intentionally omits rich text, custom fields and media metadata,
     * because those fields are the most common source of invalid response encoding.
     */
    public function buildMinimal(
        CommerceSearchQuery $query,
        ?int                $limit = 25,
        ?bool               $grouping = false
    ): array
    {
        return $this->buildCriteria(
            query: $query,
            limit: $limit,
            grouping: $grouping,
            includeRichTextFields: false,
            includeMediaFields: false,
            includeSeoUrls: false,
            includeManufacturer: false
        );
    }

    /**
     * Builds an ultra-safe Store API payload for the final recovery attempt.
     * It keeps only identity, availability and price fields and intentionally
     * avoids grouping, associations, translated text, SEO, media and custom data.
     */
    public function buildUltraSafe(
        CommerceSearchQuery $query,
        ?int                $limit = 25,
        ?bool               $grouping = false
    ): array
    {
        $criteria = [
            'page' => 1,
            'limit' => max(1, $limit),
            'total-count-mode' => 0,
            'includes' => [
                'product' => [
                    'id',
                    'productNumber',
                    'available',
                    'calculatedPrice',
                ],
                'calculated_price' => [
                    'unitPrice',
                    'totalPrice',
                    'referencePrice',
                    'listPrice',
                    'regulationPrice',
                ],
            ],
            'associations' => [],
        ];

        if ($query->searchText !== '') {
            $criteria['search'] = $query->searchText;
        }

        if ($query->priceMin !== null) {
            $criteria['min-price'] = $query->priceMin;
        }

        if ($query->priceMax !== null) {
            $criteria['max-price'] = $query->priceMax;
        }

        $criteria['filter'] = [
            [
                'type' => 'equals',
                'field' => 'active',
                'value' => true,
            ],
            [
                'type' => 'equals',
                'field' => 'available',
                'value' => true,
            ],
        ];

        return $criteria;
    }

    private function buildCriteria(
        CommerceSearchQuery $query,
        ?int $limit,
        ?bool $grouping,
        bool $includeRichTextFields,
        bool $includeMediaFields = true,
        bool $includeSeoUrls = true,
        bool $includeManufacturer = true
    ): array {
        $productIncludes = [
            'id',
            'name',
            'productNumber',
            'available',
            'calculatedPrice',
            'translated.name',
        ];

        if ($includeSeoUrls) {
            $productIncludes[] = 'seoUrls';
        }

        if ($includeManufacturer) {
            $productIncludes[] = 'manufacturer';
        }

        if ($includeMediaFields) {
            $productIncludes[] = 'cover';
        }

        if ($includeRichTextFields) {
            $productIncludes[] = 'description';
            $productIncludes[] = 'customFields';
        }

        $includes = [
            'product' => $productIncludes,
            'calculated_price' => [
                'unitPrice',
                'totalPrice',
                'referencePrice',
                'listPrice',
                'regulationPrice'
            ],
        ];

        if ($includeManufacturer) {
            $includes['product_manufacturer'] = [
                'name',
            ];
        }

        if ($includeSeoUrls) {
            $includes['seo_url'] = [
                'seoPathInfo',
            ];
        }

        if ($includeMediaFields) {
            $includes['product_media'] = [
                'id',
                'media'
            ];
            $includes['media'] = [
                'id',
                'url',
                'thumbnails',
                'alt',
                'title'
            ];
        }

        $associations = [];

        if ($includeManufacturer) {
            $associations['manufacturer'] = new \stdClass();
        }

        if ($includeSeoUrls) {
            $associations['seoUrls'] = new \stdClass();
        }

        if ($includeMediaFields) {
            $associations['cover'] = [
                'associations' => [
                    'media' => [
                        'associations' => [
                            'thumbnails' => new \stdClass()
                        ]
                    ]
                ]
            ];
        }

        $criteria = [
            'page' => 1,
            'limit' => max(1, $limit),
            'total-count-mode' => 0,
            'includes' => $includes,
            'associations' => $associations,
        ];

        if ($grouping) {
            $criteria['grouping'] = ['parentId'];
        }

        if ($query->searchText !== '') {
            $criteria['search'] = $query->searchText;
        }

        $filters = [
            [
                'type' => 'equals',
                'field' => 'active',
                'value' => true,
            ],
            [
                'type' => 'equals',
                'field' => 'available',
                'value' => true,
            ]
        ];

        if ($query->priceMin !== null) {
            $criteria['min-price'] = $query->priceMin;
        }

        if ($query->priceMax !== null) {
            $criteria['max-price'] = $query->priceMax;
        }

        $criteria['filter'] = $filters;

        return $criteria;
    }
}
