<?php

app_require('modules/economic/helpers/economic_invoice_draft.php');

use helpers\economic_invoice_draft;

if (!class_exists('EconomicInvoiceDraftItemizedDiscountProbe')) {
    class EconomicInvoiceDraftItemizedDiscountProbe extends economic_invoice_draft
    {
        public array $sentBatches = [];

        public function __construct()
        {
            $this->draft_invoice_number = 123;
            $this->currency = 'DKK';
            $this->conversion_rate = 1.0;
            $this->draft_invoice_data = (object)['draftInvoiceNumber' => 123];
        }

        protected function sendDraftLines(array $draft_lines): object
        {
            $this->sentBatches[] = $draft_lines;
            return (object)['lines' => $draft_lines];
        }
    }
}

function economic_itemized_discount_order_item(array $overrides = []): array
{
    return array_replace_recursive([
        'id' => 123,
        'quantity' => 2,
        'price' => 80,
        'reference' => '',
        'notes' => '',
        'include_in_invoice' => true,
        'product' => [
            'economic_product_id' => '5',
            'name' => 'Premium wash',
            'price' => 100,
        ],
    ], $overrides);
}

it('detects billable itemized discounts from original and final prices', function (): void {
    $pricing = economic_invoice_draft::resolveOrderItemInvoicePricing(economic_itemized_discount_order_item());

    expect($pricing['has_discount'])->toBeTrue()
        ->and($pricing['original_unit_price'])->toBe(100.0)
        ->and($pricing['final_unit_price'])->toBe(80.0)
        ->and($pricing['discount_unit_amount'])->toBe(20.0)
        ->and($pricing['discount_total_amount'])->toBe(40.0)
        ->and($pricing['discount_percentage'])->toBe(20.0);
});

it('does not mark equal prices, zero quantities, or zero final prices as itemized discounts', function (): void {
    expect(economic_invoice_draft::orderItemHasBillableDiscount(economic_itemized_discount_order_item([
        'price' => 100,
    ])))->toBeFalse();
    expect(economic_invoice_draft::orderItemHasBillableDiscount(economic_itemized_discount_order_item([
        'quantity' => 0,
    ])))->toBeFalse();
    expect(economic_invoice_draft::orderItemHasBillableDiscount(economic_itemized_discount_order_item([
        'price' => 0,
    ])))->toBeFalse();
});

it('uses original price and exact discount basis for itemized discount product lines', function (): void {
    $draft = new EconomicInvoiceDraftItemizedDiscountProbe();

    $draft->addOrderItemLine(
        economic_itemized_discount_order_item(),
        [
            'economic_department_id' => 75,
            'economic_dimension_id' => 1,
        ],
        false,
        true
    );
    $draft->flushLinesInBatches();

    $line = $draft->sentBatches[0][0];
    expect($line['product']['productNumber'])->toBe('5')
        ->and($line['description'])->toBe('Premium wash')
        ->and($line['quantity'])->toBe(2.0)
        ->and($line['unitNetPrice'])->toBe(100.0)
        ->and($line['discountPercentage'])->toBe(20.0);
});

it('keeps non-discount itemized product lines at the exact final price', function (): void {
    $draft = new EconomicInvoiceDraftItemizedDiscountProbe();

    $draft->addOrderItemLine(
        economic_itemized_discount_order_item([
            'price' => 125,
            'product' => [
                'price' => 100,
            ],
        ]),
        [
            'economic_department_id' => 75,
            'economic_dimension_id' => 1,
        ],
        false,
        true
    );
    $draft->flushLinesInBatches();

    $line = $draft->sentBatches[0][0];
    expect($line['unitNetPrice'])->toBe(125.0)
        ->and($line['discountPercentage'])->toBe(0.0);
});

it('keeps fractional discount percentages instead of rounding itemized discounts to whole percentages', function (): void {
    $pricing = economic_invoice_draft::resolveOrderItemInvoicePricing(economic_itemized_discount_order_item([
        'quantity' => 1,
        'price' => 2,
        'product' => [
            'price' => 3,
        ],
    ]));

    expect($pricing['discount_unit_amount'])->toBe(1.0)
        ->and($pricing['discount_total_amount'])->toBe(1.0)
        ->and($pricing['discount_percentage'])->toBe(33.3333333333);
});
