<?php

declare(strict_types=1);

require_once __DIR__ . '/../src/Pricing.php';
require_once __DIR__ . '/../src/ProductFilterQuery.php';

use RetailPricing\LargeSupplierOffer;
use RetailPricing\Money;
use RetailPricing\ProductPricingInput;
use RetailPricing\RetailPriceCalculator;
use RetailPricing\SupplierMarkupPolicy;
use RetailPricing\SupplierMarkupRange;
use RetailPricing\SupplierOffer;
use RetailPricing\SupplierPurchaseOffer;
use RetailPricing\SupplierSalePriceCalculator;
use RetailPricing\WarehouseLot;

function assertRub(float $expected, Money $actual, string $message): void
{
    $expectedKopecks = (int) round($expected * 100);
    if ($actual->kopecks !== $expectedKopecks) {
        throw new RuntimeException($message . ': expected ' . $expected . ', got ' . $actual->format());
    }
}

$retailCalculator = new RetailPriceCalculator();

$price = $retailCalculator->calculate(new ProductPricingInput(
    smallSupplierOffers: [
        new SupplierOffer(1, Money::rub(1300), 2),
        new SupplierOffer(2, Money::rub(1250), 0),
    ],
    largeSupplierOffers: [
        new LargeSupplierOffer(10, Money::rub(1260), Money::rub(1180), 5),
    ],
    warehouseLots: [
        new WarehouseLot(Money::rub(1000), Money::rub(1600), 1),
    ],
    minMarkupPercent: 30,
));
assertRub(1300, $price, 'Own stock cannot be sold below purchase plus minimal markup');

$price = $retailCalculator->calculate(new ProductPricingInput(
    smallSupplierOffers: [],
    largeSupplierOffers: [
        new LargeSupplierOffer(10, Money::rub(1600), Money::rub(1420), 1),
        new LargeSupplierOffer(11, Money::rub(1550), Money::rub(1390), 3),
    ],
    warehouseLots: [],
    minMarkupPercent: 30,
));
assertRub(1390, $price, 'No own stock must use minimal calculated large supplier price');

$price = $retailCalculator->calculate(new ProductPricingInput(
    smallSupplierOffers: [],
    largeSupplierOffers: [],
    warehouseLots: [
        new WarehouseLot(Money::rub(1000), Money::rub(1320), 1),
    ],
    minMarkupPercent: 30,
));
assertRub(1320, $price, 'No suppliers must use validated warehouse sale price');

$supplierSaleCalculator = new SupplierSalePriceCalculator();
$calculated = $supplierSaleCalculator->calculate(
    purchaseOffers: [
        new SupplierPurchaseOffer(1, Money::rub(499), 2),
        new SupplierPurchaseOffer(1, Money::rub(999), 1),
        new SupplierPurchaseOffer(2, Money::rub(2000), 1),
        new SupplierPurchaseOffer(3, Money::rub(1000), 1),
    ],
    policiesBySupplierId: [
        1 => new SupplierMarkupPolicy(1, [
            new SupplierMarkupRange(Money::rub(0), Money::rub(499), 45),
            new SupplierMarkupRange(Money::rub(500), Money::rub(999), 40),
            new SupplierMarkupRange(Money::rub(1000), Money::rub(4999), 35),
        ]),
        2 => new SupplierMarkupPolicy(2, [], discountlessMarkupPercent: 50),
    ],
    discountless: true,
);

assertRub(723.55, $calculated[0]->salePrice, 'Supplier range markup for 0..499');
assertRub(1398.60, $calculated[1]->salePrice, 'Supplier range markup for 500..999');
assertRub(3000, $calculated[2]->salePrice, 'Discountless supplier markup');
assertRub(1250, $calculated[3]->salePrice, 'Default markup');

echo "OK: pricing scenarios and supplier sale price calculation passed.\n";
echo "\nSQL filter example:\n";
echo RetailPricing\ProductFilterQuery::sql() . "\n";
