<?php

app_require('classes/response.php');
app_require('routes/InvoicingPeriodRoute.php');

use classes\response;
use routes\InvoicingPeriodRoute;

function invoicing_period_pagination_invoke(string $method, array $args = []): mixed
{
    $reflection = new ReflectionClass(InvoicingPeriodRoute::class);
    $target = $reflection->getMethod($method);
    return $target->invokeArgs(null, $args);
}

function invoicing_period_customer_card(
    int $customerNumber,
    string $customerName,
    array $transactions,
    bool $requiresAction = false,
    array $extra = []
): array {
    return array_merge([
        'id' => $customerNumber,
        'customer_number' => $customerNumber,
        'customer_name' => $customerName,
        'requires_action' => $requiresAction,
        'transactions' => $transactions,
        'meta' => [],
        'queue' => [
            'has_active_job' => false,
            'statuses' => [],
            'invoice_collection_ids' => [],
            'is_action_blocked' => false,
        ],
        'draft' => [
            'has_valid_draft' => false,
            'invoice_collection_ids' => [],
            'is_action_blocked' => false,
        ],
    ], $extra);
}

function invoicing_period_transaction(array $overrides = []): array
{
    return array_merge([
        'id' => 9001,
        'date' => '2026-04-10 12:00:00',
        'amount' => 125.5,
        'booked' => false,
        'department_id' => 1,
        'customer_number' => 1001,
        'reference' => 'REF-9001',
        'po' => 'PO-9001',
        'notes' => 'Gate note',
        'reg_1' => 'AB12345',
        'reg_2' => '',
        'reg_3' => '',
        'excluded' => false,
        'invoice_collection_id' => 3001,
        'queue_status' => null,
        'queue_job_id' => null,
    ], $overrides);
}

it('detects paginated period mode only when pagination parameters are present', function (): void {
    global $response;

    $previousResponse = $GLOBALS['response'] ?? null;
    $previousGet = $_GET;
    $previousMethod = $_SERVER['REQUEST_METHOD'] ?? null;
    $response = new response();

    try {
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_GET = [
            'dateFrom' => '2026-04-01',
            'dateTo' => '2026-04-30',
        ];

        expect(invoicing_period_pagination_invoke('getPeriodPaginationOptionsFromRequest'))->toBeNull();

        $_GET['page'] = '2';
        expect(invoicing_period_pagination_invoke('getPeriodPaginationOptionsFromRequest'))->toMatchArray([
            'periodView' => 'all',
            'page' => 2,
            'limit' => 100,
            'search' => '',
            'includeRequiresAction' => true,
            'includeBooked' => true,
        ]);
    } finally {
        $_GET = $previousGet;
        if ($previousMethod === null) {
            unset($_SERVER['REQUEST_METHOD']);
        } else {
            $_SERVER['REQUEST_METHOD'] = $previousMethod;
        }
        if ($previousResponse === null) {
            unset($GLOBALS['response']);
        } else {
            $response = $previousResponse;
        }
    }
});

it('normalizes period pagination options and clamps invalid page and limit values', function (): void {
    $options = invoicing_period_pagination_invoke('normalizePeriodPaginationOptions', [[
        'periodView' => 'not-a-view',
        'page' => '-4',
        'limit' => '500',
        'search' => '  Nordic  ',
        'includeRequiresAction' => '0',
        'includeBooked' => 'false',
        'flagTab' => 'invalid-tab',
    ]]);

    expect($options)->toBe([
        'periodView' => 'all',
        'page' => 1,
        'limit' => 500,
        'search' => 'Nordic',
        'flagTab' => 'all',
        'includeRequiresAction' => false,
        'includeBooked' => false,
    ]);

    expect(invoicing_period_pagination_invoke('normalizePeriodPaginationOptions', [[
        'limit' => '900',
    ]]))->toMatchArray([
        'limit' => 500,
    ]);

    expect(invoicing_period_pagination_invoke('normalizePeriodPaginationOptions', [[
        'limit' => 'all',
    ]]))->toMatchArray([
        'limit' => 'all',
    ]);

    expect(invoicing_period_pagination_invoke('normalizePeriodPaginationOptions', [[
        'periodView' => 'invoice_per_order',
        'page' => '3',
        'limit' => '0',
        'flagTab' => 'yellow',
    ]]))->toMatchArray([
        'periodView' => 'invoice_per_order',
        'page' => 3,
        'limit' => 100,
        'flagTab' => 'yellow',
    ]);
});

it('slices only the active period view and keeps exact full-result type counts', function (): void {
    $period = [
        'dateFrom' => '2026-04-01 00:00:00',
        'dateTo' => '2026-04-30 23:59:59',
        'types' => [
            'all' => [
                invoicing_period_customer_card(1001, 'Alpha Transport', [
                    invoicing_period_transaction(['id' => 11, 'customer_number' => 1001, 'amount' => 50]),
                ], false),
                invoicing_period_customer_card(1002, 'Beta Transport', [
                    invoicing_period_transaction([
                        'id' => 12,
                        'customer_number' => 1002,
                        'amount' => 75,
                        'booked' => true,
                        'excluded' => true,
                        'reference' => 'REF-BETA',
                        'po' => 'PO-BETA',
                        'reg_1' => 'BB22222',
                    ]),
                ], true),
                invoicing_period_customer_card(1003, 'Gamma Transport', [
                    invoicing_period_transaction([
                        'id' => 13,
                        'customer_number' => 1003,
                        'amount' => 125,
                        'booked' => true,
                    ]),
                ], false, [
                    'draft' => [
                        'has_valid_draft' => true,
                        'invoice_collection_ids' => [3013],
                        'is_action_blocked' => true,
                    ],
                ]),
            ],
            'fixed_pricing' => [
                invoicing_period_customer_card(1002, 'Beta Transport', [], true, [
                    'meta' => [
                        'fixed_pricing' => [
                            'price' => 999,
                        ],
                    ],
                ]),
            ],
            'invoice_per_order' => [
                invoicing_period_customer_card(1001, 'Alpha Transport', [], true, [
                    'flags' => [
                        ['source' => 'manual', 'status' => 'active'],
                    ],
                ]),
            ],
        ],
    ];

    $result = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 2,
        'limit' => 1,
        'search' => '',
        'includeRequiresAction' => true,
        'includeBooked' => true,
    ]]);

    expect($result['pagination'])->toMatchArray([
        'page' => 2,
        'per_page' => 1,
        'total' => 3,
        'search' => '',
    ]);

    expect($result['period']['types']['all'])->toHaveCount(1);
    expect($result['period']['types']['all'][0])->toMatchArray([
        'customer_number' => 1002,
        'customer_name' => 'Beta Transport',
        'requires_action' => true,
        'meta' => [
            'fixed_pricing' => [
                'price' => 999,
            ],
        ],
    ]);
    expect($result['period']['types']['all'][0]['transactions'][0])->toMatchArray([
        'id' => 12,
        'amount' => 75,
        'booked' => true,
        'excluded' => true,
        'reference' => 'REF-BETA',
        'po' => 'PO-BETA',
        'reg_1' => 'BB22222',
    ]);
    expect($result['period']['types']['fixed_pricing'])->toBe([]);
    expect($result['period']['type_counts']['all'])->toBe([
        'requires_action' => 1,
        'draft' => 1,
        'manual_flags' => 0,
        'automatic_flags' => 0,
        'completed' => 1,
        'total' => 3,
    ]);
    expect($result['period']['type_totals']['all'])->toBe([
        'total' => 1174.0,
        'booked' => 125.0,
        'not_booked' => 1049.0,
    ]);
    expect($result['period']['type_totals']['fixed_pricing'])->toBe([
        'total' => 999.0,
        'booked' => 0.0,
        'not_booked' => 999.0,
    ]);
    expect($result['period']['type_counts']['invoice_per_order']['manual_flags'])->toBe(1);
});

it('returns the entire active period view when the limit is all', function (): void {
    $period = [
        'dateFrom' => '2026-04-01 00:00:00',
        'dateTo' => '2026-04-30 23:59:59',
        'types' => [
            'all' => [
                invoicing_period_customer_card(1101, 'Alpha', [
                    invoicing_period_transaction(['id' => 31, 'customer_number' => 1101]),
                ]),
                invoicing_period_customer_card(1102, 'Beta', [
                    invoicing_period_transaction(['id' => 32, 'customer_number' => 1102]),
                ]),
                invoicing_period_customer_card(1103, 'Gamma', [
                    invoicing_period_transaction(['id' => 33, 'customer_number' => 1103]),
                ]),
            ],
        ],
    ];

    $result = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 3,
        'limit' => 'all',
        'search' => '',
        'includeRequiresAction' => true,
        'includeBooked' => true,
    ]]);

    expect($result['pagination'])->toMatchArray([
        'page' => 1,
        'per_page' => 'all',
        'total' => 3,
    ]);
    expect(array_column($result['period']['types']['all'], 'customer_number'))->toBe([1101, 1102, 1103]);
});

it('searches customer fields and order fields at the customer-card level', function (): void {
    $period = [
        'dateFrom' => '2026-04-01 00:00:00',
        'dateTo' => '2026-04-30 23:59:59',
        'types' => [
            'all' => [
                invoicing_period_customer_card(2001, 'Solaris Fleet', [
                    invoicing_period_transaction([
                        'id' => 21,
                        'customer_number' => 2001,
                        'reference' => 'REF-KEEP',
                        'po' => 'PO-KEEP',
                    ]),
                ]),
                invoicing_period_customer_card(2002, 'Nordic Logistics', [
                    invoicing_period_transaction([
                        'id' => 22,
                        'customer_number' => 2002,
                        'reference' => 'MISS',
                        'po' => 'PO-777',
                        'notes' => 'Driver waits at gate',
                        'reg_1' => 'CD33333',
                    ]),
                    invoicing_period_transaction([
                        'id' => 23,
                        'customer_number' => 2002,
                        'reference' => 'SECOND-LINE',
                    ]),
                ]),
            ],
        ],
    ];

    $result = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 1,
        'limit' => 25,
        'search' => 'po-777',
        'includeRequiresAction' => true,
        'includeBooked' => true,
    ]]);

    expect($result['pagination']['total'])->toBe(1);
    expect($result['period']['types']['all'])->toHaveCount(1);
    expect($result['period']['types']['all'][0]['customer_number'])->toBe(2002);
    expect($result['period']['types']['all'][0]['transactions'])->toHaveCount(2);

    $registrationMatch = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 1,
        'limit' => 25,
        'search' => 'cd33333',
        'includeRequiresAction' => true,
        'includeBooked' => true,
    ]]);
    expect($registrationMatch['period']['types']['all'][0]['customer_name'])->toBe('Nordic Logistics');
});

it('applies requires-action and booked visibility filters before counting and slicing', function (): void {
    $period = [
        'dateFrom' => '2026-04-01 00:00:00',
        'dateTo' => '2026-04-30 23:59:59',
        'types' => [
            'all' => [
                invoicing_period_customer_card(3001, 'Needs Action', [
                    invoicing_period_transaction(['customer_number' => 3001, 'booked' => false]),
                ], true),
                invoicing_period_customer_card(3002, 'Already Booked', [
                    invoicing_period_transaction(['customer_number' => 3002, 'booked' => true]),
                ], false),
                invoicing_period_customer_card(3003, 'Still Open', [
                    invoicing_period_transaction(['customer_number' => 3003, 'booked' => false]),
                ], false),
            ],
        ],
    ];

    $result = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 1,
        'limit' => 25,
        'search' => '',
        'includeRequiresAction' => false,
        'includeBooked' => false,
    ]]);

    expect($result['pagination']['total'])->toBe(1);
    expect($result['period']['type_counts']['all']['total'])->toBe(1);
    expect($result['period']['types']['all'][0]['customer_number'])->toBe(3003);
});

it('filters period flag tabs using active customer-scoped flag counts', function (): void {
    $period = [
        'dateFrom' => '2026-04-01 00:00:00',
        'dateTo' => '2026-04-30 23:59:59',
        'types' => [
            'all' => [
                invoicing_period_customer_card(4001, 'Yellow Order Flag', [
                    invoicing_period_transaction(['customer_number' => 4001, 'id' => 41]),
                ], false, [
                    'flags' => [
                        [
                            'source' => 'automatic',
                            'status' => 'active',
                            'target_type' => 'order',
                            'order_id' => 41,
                        ],
                    ],
                ]),
                invoicing_period_customer_card(4002, 'Ignored Manual Flag', [
                    invoicing_period_transaction(['customer_number' => 4002, 'id' => 42]),
                ], false, [
                    'flags' => [
                        [
                            'source' => 'manual',
                            'status' => 'ignored',
                            'target_type' => 'customer',
                        ],
                    ],
                ]),
                invoicing_period_customer_card(4003, 'Red Customer Flag', [
                    invoicing_period_transaction(['customer_number' => 4003, 'id' => 43]),
                ], false, [
                    'flags' => [
                        [
                            'source' => 'manual',
                            'status' => 'active',
                            'target_type' => 'customer',
                        ],
                    ],
                ]),
            ],
        ],
    ];

    $yellowResult = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 1,
        'limit' => 25,
        'search' => '',
        'flagTab' => 'yellow',
        'includeRequiresAction' => true,
        'includeBooked' => true,
    ]]);

    expect($yellowResult['pagination']['total'])->toBe(1);
    expect(array_column($yellowResult['period']['types']['all'], 'customer_number'))->toBe([4001]);

    $noneResult = invoicing_period_pagination_invoke('applyPeriodPagination', [$period, [
        'periodView' => 'all',
        'page' => 1,
        'limit' => 25,
        'search' => '',
        'flagTab' => 'none',
        'includeRequiresAction' => true,
        'includeBooked' => true,
    ]]);

    expect($noneResult['pagination']['total'])->toBe(1);
    expect(array_column($noneResult['period']['types']['all'], 'customer_number'))->toBe([4002]);
    expect($noneResult['period']['type_counts']['all'])->toMatchArray([
        'manual_flags' => 1,
        'automatic_flags' => 1,
        'total' => 3,
    ]);
});
