<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>

        <!-- ── Ultimate Cart dedicated log file ─────────────────────────────────
             Shopware's production logging uses Monolog's "fingers_crossed"
             handler on the default channel: records for a request are
             buffered and only written to prod.log if something in that SAME
             request reaches ERROR level — debug/info/warning records (most
             of what this plugin logs) are silently dropped in production
             otherwise.

             This builds a plain Monolog\Logger service directly (NOT via a
             Resources/config/packages/*.yaml "monolog:" block — Shopware
             plugins do not auto-load those the way the main app's
             config/packages/ does; an earlier attempt at that broke
             cache:clear with "non-existent service
             monolog.logger.sellops_ultimate_cart"). A plain service
             definition here only depends on services.xml itself, which IS
             always auto-loaded for every plugin, and on the Monolog classes
             Shopware core already requires.

             Every LoggerInterface argument below now points at this service
             instead of the generic "logger", so plugin logs always reach
             their own file regardless of environment.

             Log file: var/log/sellops-ultimate-cart-<environment>.log
        -->
        <service id="Sellops\UltimateCart\Logger\CartRotatingFileHandler" class="Monolog\Handler\RotatingFileHandler">
            <argument>%kernel.logs_dir%/sellops-ultimate-cart-%kernel.environment%.log</argument>
            <argument>14</argument>
        </service>

        <service id="Sellops\UltimateCart\Logger\UltimateCartLogger" class="Monolog\Logger" public="false">
            <argument>sellops_ultimate_cart</argument>
            <call method="pushHandler">
                <argument type="service" id="Sellops\UltimateCart\Logger\CartRotatingFileHandler"/>
            </call>
        </service>

        <!-- ── Progress Milestone entity ──────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Entity\ProgressMilestone\ProgressMilestoneDefinition">
            <tag name="shopware.entity.definition" entity="sellops_uc_progress_milestone"/>
        </service>

        <!-- ── Free Product entity ────────────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Entity\FreeProduct\FreeProductDefinition">
            <tag name="shopware.entity.definition" entity="sellops_uc_free_product"/>
        </service>

        <!-- ── Cross-Sell Rule entity ─────────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Entity\CrossSellRule\CrossSellRuleDefinition">
            <tag name="shopware.entity.definition" entity="sellops_uc_cross_sell_rule"/>
        </service>

        <!-- ── FreeProductGiftResolver ────────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Service\FreeProductGiftResolver">
            <argument type="service" id="sellops_uc_free_product.repository"/>
            <argument type="service" id="sales_channel.product.repository"/>
            <argument type="service" id="order_line_item.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Service\VariantOptionLoader"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
        </service>

        <!-- ── ActiveMilestoneLoader ─────────────────────────────────────────── -->
        <!--
            Single source of truth for "active milestones in scope for this
            sales channel" — shared by ProgressBarResolver, MilestoneCartProcessor,
            and MilestoneFixedCodePromotionSync so they can never silently
            disagree on the starting set of milestones. Shopware auto-creates
            sellops_uc_progress_milestone.repository from the entity definition
            tag above; this is the only service that injects it directly.
        -->
        <service id="Sellops\UltimateCart\Service\ActiveMilestoneLoader">
            <argument type="service" id="sellops_uc_progress_milestone.repository"/>
        </service>

        <!-- ── VariantOptionLoader ───────────────────────────────────────────── -->
        <!-- Shared variant/option data for the gift and cross-sell popups -->
        <service id="Sellops\UltimateCart\Service\VariantOptionLoader">
            <argument type="service" id="product.repository"/>
            <argument type="service" id="sales_channel.product.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
        </service>

        <service id="Sellops\UltimateCart\Service\ProgressBarResolver">
            <argument type="service" id="Sellops\UltimateCart\Service\ActiveMilestoneLoader"/>
            <argument type="service" id="Sellops\UltimateCart\Service\FreeProductGiftResolver"/>
            <argument type="service" id="promotion.repository"/>
            <argument type="service" id="media.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
        </service>

        <!-- ── MilestoneCartProcessor ────────────────────────────────────────── -->
        <!--
            Applies discount_percent, discount_fixed, and free_shipping rewards
            directly inside the cart calculation pipeline (CartProcessorInterface).
            Priority -50 runs after product processors (~0) so prices are already
            calculated when we read them for percentage/absolute discount math.
        -->
        <service id="Sellops\UltimateCart\Cart\MilestoneCartProcessor">
            <argument type="service" id="Sellops\UltimateCart\Service\ActiveMilestoneLoader"/>
            <argument type="service" id="product.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Service\FreeProductGiftResolver"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\Price\PercentagePriceCalculator"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\Price\AbsolutePriceCalculator"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
            <tag name="shopware.cart.processor" priority="-50"/>
        </service>

        <!-- ── StorefrontPageSubscriber ───────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Subscriber\StorefrontPageSubscriber">
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
            <argument type="service" id="Sellops\UltimateCart\Service\CrossSellResolver"/>
            <argument type="service" id="Sellops\UltimateCart\Service\ProgressBarResolver"/>
            <argument type="service" id="Sellops\UltimateCart\Service\FreeProductGiftResolver"/>
            <argument type="service" id="Sellops\UltimateCart\Service\MilestoneFixedCodePromotionSync"/>
            <argument type="service" id="media.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
            <tag name="kernel.event_subscriber"/>
        </service>

        <!-- ── CrossSellResolver ─────────────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Service\CrossSellResolver">
            <argument type="service" id="product.repository"/>
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
            <argument type="service" id="Sellops\UltimateCart\Service\VariantOptionLoader"/>
            <argument type="service" id="Sellops\UltimateCart\Service\CrossSellRuleEngine"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
        </service>

        <!-- ── CrossSellFrequentlyBoughtTogetherService ─────────────────────────── -->
        <service id="Sellops\UltimateCart\Service\CrossSellFrequentlyBoughtTogetherService">
            <argument type="service" id="Doctrine\DBAL\Connection"/>
        </service>

        <!-- ── CrossSellRuleEngine ───────────────────────────────────────────────
             Evaluates sellops_uc_cross_sell_rule entries against the CURRENT
             CART CONTENTS and resolves the mini-cart's "Cross-Sell" offers.
             sales_channel.product.repository gives cover/media/tax/prices
             populated the same way CrossSellResolver's own native fallback does.
        -->
        <service id="Sellops\UltimateCart\Service\CrossSellRuleEngine">
            <argument type="service" id="Doctrine\DBAL\Connection"/>
            <argument type="service" id="sales_channel.product.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Service\CrossSellFrequentlyBoughtTogetherService"/>
            <argument type="service" id="Shopware\Core\Content\ProductStream\Service\ProductStreamBuilder"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
            <argument type="service" id="sellops_uc_cross_sell_rule.repository"/>
        </service>

        <!-- ── CrossSellRulesAdminController ─────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Controller\Admin\CrossSellRulesAdminController" public="true">
            <argument type="service" id="Doctrine\DBAL\Connection"/>
            <argument type="service" id="sellops_uc_cross_sell_rule.repository"/>
            <call method="setContainer">
                <argument type="service" id="service_container"/>
            </call>
        </service>

        <!-- ── CrossSellDiscountCartProcessor ─────────────────────────────────
             Applies the cross-sell rule builder's discount to the REAL price
             of matching product line items — without this, the discounted
             price shown in the mini-cart's Cross-Sell offer card was purely
             cosmetic and the customer was charged full price. Re-evaluates
             CrossSellRuleEngine server-side (same call CrossSellResolver
             makes for display) rather than trusting any client-supplied
             discount value. Priority -50 matches MilestoneCartProcessor —
             runs after ProductCartProcessor (~5000) has already priced items.
        -->
        <service id="Sellops\UltimateCart\Cart\CrossSellDiscountCartProcessor">
            <argument type="service" id="Doctrine\DBAL\Connection"/>
            <argument type="service" id="sales_channel.product.repository"/>
            <argument type="service" id="Sellops\UltimateCart\Service\CrossSellRuleEngine"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\Price\QuantityPriceCalculator"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
            <tag name="shopware.cart.processor" priority="-50"/>
        </service>

        <!-- ── MilestoneFixedCodePromotionSync ──────────────────────────────────── -->
        <!--
            Auto-redeems / auto-removes a Fixed-code Promotion (one shared code,
            not per-customer) when a milestone's threshold is crossed. Triggered
            by CartChangedSubscriber below — see that class + this service's own
            docblock for why it can't live inside MilestoneCartProcessor.
        -->
        <service id="Sellops\UltimateCart\Service\MilestoneFixedCodePromotionSync">
            <argument type="service" id="Sellops\UltimateCart\Service\ActiveMilestoneLoader"/>
            <argument type="service" id="promotion.repository"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
        </service>

        <!-- ── MilestoneFreeGiftSync ────────────────────────────────────────────── -->
        <!--
            Auto-adds a non-variant free-product gift the moment its milestone
            is reached (no "Add" click needed). Triggered by CartChangedSubscriber
            below — see that class + this service's own docblock for why it
            can't live inside MilestoneCartProcessor, and why removal needs no
            matching call here.
        -->
        <service id="Sellops\UltimateCart\Service\MilestoneFreeGiftSync">
            <argument type="service" id="Sellops\UltimateCart\Service\FreeProductGiftResolver"/>
            <argument type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
        </service>

        <!-- ── CartChangedSubscriber ─────────────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Subscriber\CartChangedSubscriber">
            <argument type="service" id="Sellops\UltimateCart\Service\MilestoneFixedCodePromotionSync"/>
            <argument type="service" id="Sellops\UltimateCart\Service\MilestoneFreeGiftSync"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
            <tag name="kernel.event_subscriber"/>
        </service>

        <!-- ── ProductStickyCartSubscriber ───────────────────────────────────── -->
        <service id="Sellops\UltimateCart\Subscriber\ProductStickyCartSubscriber">
            <argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
            <argument type="service" id="Sellops\UltimateCart\Logger\UltimateCartLogger"/>
            <tag name="kernel.event_subscriber"/>
        </service>

    </services>

</container>
