<?php

namespace Tests\Unit\B2B;

use Mtc\Modules\B2B\Models\TradeTier;
use Mtc\Modules\B2B\Services\TradePricingService;
use Mtc\Shop\Item;
use Mtc\Shop\Item\Size;
use Tests\TestCase;

class TradePricingServiceTest extends TestCase
{
    private TradePricingService $service;

    protected function setUp(): void
    {
        parent::setUp();
        $this->service = new TradePricingService();
    }

    private function makeItem(array $attributes = []): Item
    {
        $item = new Item();
        $item->trade_price = $attributes['trade_price'] ?? null;
        $item->trade_price_exvat = $attributes['trade_price_exvat'] ?? null;
        $item->trade_sale_price = $attributes['trade_sale_price'] ?? null;
        $item->trade_sale_price_exvat = $attributes['trade_sale_price_exvat'] ?? null;
        $item->price = $attributes['price'] ?? 0;
        $item->price_exvat = $attributes['price_exvat'] ?? 0;
        return $item;
    }

    private function makeSize(array $attributes = []): Size
    {
        $size = new Size();
        $size->trade_price = $attributes['trade_price'] ?? null;
        $size->trade_price_exvat = $attributes['trade_price_exvat'] ?? null;
        $size->trade_sale_price = $attributes['trade_sale_price'] ?? null;
        $size->trade_sale_price_exvat = $attributes['trade_sale_price_exvat'] ?? null;
        return $size;
    }

    private function makeTier(float $discount): TradeTier
    {
        $tier = new TradeTier();
        $tier->discount_percentage = $discount;
        return $tier;
    }

    public function test_basic_tier_discount_calculation()
    {
        $item = $this->makeItem(['trade_price' => 100.00]);
        $tier = $this->makeTier(7.5);

        $result = $this->service->calculatePrice($item, null, $tier);

        $this->assertEquals(92.50, $result);
    }

    public function test_trade_sale_price_wins_when_lower()
    {
        $item = $this->makeItem([
            'trade_price' => 100.00,
            'trade_sale_price' => 85.00,
        ]);
        $tier = $this->makeTier(10); // discount would give 90.00

        $result = $this->service->calculatePrice($item, null, $tier);

        $this->assertEquals(85.00, $result);
    }

    public function test_trade_sale_price_ignored_when_higher_than_discounted()
    {
        $item = $this->makeItem([
            'trade_price' => 100.00,
            'trade_sale_price' => 95.00,
        ]);
        $tier = $this->makeTier(10); // discount gives 90.00

        $result = $this->service->calculatePrice($item, null, $tier);

        $this->assertEquals(90.00, $result);
    }

    public function test_null_trade_price_returns_null()
    {
        $item = $this->makeItem(['trade_price' => null]);
        $tier = $this->makeTier(10);

        $result = $this->service->calculatePrice($item, null, $tier);

        $this->assertNull($result);
    }

    public function test_size_level_trade_price_overrides_item_level()
    {
        $item = $this->makeItem(['trade_price' => 100.00]);
        $size = $this->makeSize(['trade_price' => 80.00]);
        $tier = $this->makeTier(10);

        $result = $this->service->calculatePrice($item, $size, $tier);

        // Size price of 80 with 10% discount = 72
        $this->assertEquals(72.00, $result);
    }

    public function test_zero_discount_tier()
    {
        $item = $this->makeItem(['trade_price' => 50.00]);
        $tier = $this->makeTier(0);

        $result = $this->service->calculatePrice($item, null, $tier);

        $this->assertEquals(50.00, $result);
    }

    public function test_rounding_to_penny()
    {
        $item = $this->makeItem(['trade_price' => 33.33]);
        $tier = $this->makeTier(7.5);

        $result = $this->service->calculatePrice($item, null, $tier);

        // 33.33 * (1 - 0.075) = 33.33 * 0.925 = 30.83025 → rounded to 30.83
        $this->assertEquals(30.83, $result);
    }

    public function test_savings_percentage_calculation()
    {
        $item = $this->makeItem(['trade_price' => 100.00]);
        $tier = $this->makeTier(10);

        $result = $this->service->getSavingsPercentage($item, null, $tier);

        $this->assertEquals(10.0, $result);
    }

    public function test_savings_percentage_with_trade_sale_price()
    {
        $item = $this->makeItem([
            'trade_price' => 100.00,
            'trade_sale_price' => 80.00,
        ]);
        $tier = $this->makeTier(5); // discount gives 95.00, but sale price 80 wins

        $result = $this->service->getSavingsPercentage($item, null, $tier);

        // Original trade price: 100. Final price: 80. Savings = 20%
        $this->assertEquals(20.0, $result);
    }

    public function test_savings_percentage_null_when_no_trade_price()
    {
        $item = $this->makeItem(['trade_price' => null]);
        $tier = $this->makeTier(10);

        $result = $this->service->getSavingsPercentage($item, null, $tier);

        $this->assertNull($result);
    }

    public function test_original_trade_price_uses_size_when_available()
    {
        $item = $this->makeItem(['trade_price' => 100.00]);
        $size = $this->makeSize(['trade_price' => 80.00]);

        $result = $this->service->getOriginalTradePrice($item, $size);

        $this->assertEquals(80.00, $result);
    }

    public function test_original_trade_price_falls_back_to_item()
    {
        $item = $this->makeItem(['trade_price' => 100.00]);
        $size = $this->makeSize(['trade_price' => null]);

        $result = $this->service->getOriginalTradePrice($item, $size);

        $this->assertEquals(100.00, $result);
    }

    public function test_size_with_null_trade_price_falls_back_to_item()
    {
        $item = $this->makeItem(['trade_price' => 100.00]);
        $size = $this->makeSize(['trade_price' => null]);
        $tier = $this->makeTier(10);

        $result = $this->service->calculatePrice($item, $size, $tier);

        // Falls back to item trade price: 100 * 0.9 = 90
        $this->assertEquals(90.00, $result);
    }
}
