<?php

app_require('classes/economic_v2_compare_engine.php');

use classes\economic_v2_compare_engine;

function economic_v2_test_invoice(array $overrides = []): array
{
    $base = [
        'source' => 'internal',
        'totals' => [
            'net_total' => 100.0,
            'line_net_total' => 100.0,
            'line_count' => 1,
            'billable_line_count' => 1,
        ],
        'departments' => [
            '75' => 100.0,
        ],
        'lines' => [
            [
                'source' => 'internal',
                'source_line_id' => 1,
                'line_type' => 'product',
                'billable' => true,
                'product_number' => '1',
                'description' => 'Trakker',
                'reference' => '',
                'quantity' => 1.0,
                'unit_net_price' => 100.0,
                'line_net_amount' => 100.0,
                'department_distribution' => ['75' => 100.0],
                'match_key' => 'product:1|ref:',
            ],
        ],
        'warnings' => [],
    ];

    return array_replace_recursive($base, $overrides);
}

it('returns exact_match when totals lines and departments are identical', function (): void {
    $internal = economic_v2_test_invoice();
    $draft = economic_v2_test_invoice(['source' => 'draft']);
    $booked = economic_v2_test_invoice(['source' => 'booked']);

    $result = economic_v2_compare_engine::compare($internal, $draft, $booked);

    expect($result['targets']['draft']['status'])->toBe('exact_match');
    expect($result['targets']['booked']['status'])->toBe('exact_match');
    expect($result['targets']['draft']['overall_match'])->toBeTrue();
    expect($result['targets']['booked']['overall_match'])->toBeTrue();
});

it('returns total_mismatch when only totals differ', function (): void {
    $internal = economic_v2_test_invoice();
    $draft = economic_v2_test_invoice([
        'source' => 'draft',
        'totals' => ['net_total' => 125.0],
    ]);

    $result = economic_v2_compare_engine::compareTarget($internal, $draft, 'draft');

    expect($result['status'])->toBe('total_mismatch');
    expect($result['totals']['matches'])->toBeFalse();
    expect($result['mismatch_reasons'])->toContain('total_mismatch');
});

it('detects line-level mismatches for quantity and price', function (): void {
    $internal = economic_v2_test_invoice();
    $draft = economic_v2_test_invoice([
        'source' => 'draft',
        'lines' => [[
            'source' => 'draft',
            'source_line_id' => 1,
            'line_type' => 'product',
            'billable' => true,
            'product_number' => '1',
            'description' => 'Trakker',
            'reference' => '',
            'quantity' => 2.0,
            'unit_net_price' => 95.0,
            'line_net_amount' => 190.0,
            'department_distribution' => ['75' => 100.0],
            'match_key' => 'product:1|ref:',
        ]],
        'totals' => ['net_total' => 100.0],
        'departments' => ['75' => 100.0],
    ]);

    $result = economic_v2_compare_engine::compareTarget($internal, $draft, 'draft');
    $reasons = $result['lines']['diff'][0]['reasons'] ?? [];

    expect($result['lines']['summary']['mismatch_count'])->toBeGreaterThan(0);
    expect($reasons)->toContain('quantity_mismatch');
    expect($reasons)->toContain('unit_price_mismatch');
});

it('detects departmental distribution mismatches', function (): void {
    $internal = economic_v2_test_invoice();
    $draft = economic_v2_test_invoice([
        'source' => 'draft',
        'lines' => [[
            'source' => 'draft',
            'source_line_id' => 1,
            'line_type' => 'product',
            'billable' => true,
            'product_number' => '1',
            'description' => 'Trakker',
            'reference' => '',
            'quantity' => 1.0,
            'unit_net_price' => 100.0,
            'line_net_amount' => 100.0,
            'department_distribution' => ['10' => 100.0],
            'match_key' => 'product:1|ref:',
        ]],
        'departments' => ['10' => 100.0],
    ]);

    $result = economic_v2_compare_engine::compareTarget($internal, $draft, 'draft');
    $lineReasons = $result['lines']['diff'][0]['reasons'] ?? [];

    expect($lineReasons)->toContain('departmental_distribution_mismatch');
    expect($result['departments']['matches'])->toBeFalse();
    expect($result['mismatch_reasons'])->toContain('department_total_mismatch');
});

it('returns missing_target when draft or booked target is unavailable', function (): void {
    $internal = economic_v2_test_invoice();
    $result = economic_v2_compare_engine::compareTarget($internal, null, 'booked');

    expect($result['status'])->toBe('missing_target');
    expect($result['overall_match'])->toBeFalse();
    expect($result['mismatch_reasons'])->toContain('missing_target');
});
