<?php

app_require('modules/selfserve/traits/selfserve_lane_invoice_t.php');
app_require('modules/selfserve/helpers/selfserve_lane_mode.php');
app_require('modules/selfserve/helpers/selfserve_lane_status.php');
app_require('objects/orders_o.php');

use modules\selfserve\helpers\selfserve_lane_mode;
use modules\selfserve\helpers\selfserve_lane_status;
use modules\selfserve\traits\selfserve_lane_invoice_t;
use objects\orders_o;

class SelfserveLaneInvoiceModeOrderStub extends orders_o
{
    public ?int $attachedBillingCustomerNumber = null;
    public ?int $attachedDraftCustomerNumber = null;

    public function __construct() {}
}

class SelfserveLaneInvoiceModeBillingHarness
{
    use selfserve_lane_invoice_t;

    public int $id = 101;

    public ?int $lastAddedOrderId = null;
    public ?int $lastAddedProductId = null;
    public ?int $lastAddedQuantity = null;
    public int $createdOrderContexts = 0;
    public ?int $lastOrderCustomerNumber = null;
    public ?int $lastAttachmentBillingCustomerNumber = null;
    public ?int $lastAttachmentDraftCustomerNumber = null;

    private selfserve_lane_status $laneStatus = selfserve_lane_status::OCCUPIED;
    private selfserve_lane_mode $laneMode = selfserve_lane_mode::MANUAL;
    private int $customerNumber = 1234;
    private string $licensePlate = 'AB12345';
    private int $elapsedWashTimeSeconds = 0;
    private int $minuteBillingProductId = 999;
    private int $includedMinutes = 0;
    private ?int $draftCustomerNumber = null;

    public function setLaneModeForTest(selfserve_lane_mode $mode): void
    {
        $this->laneMode = $mode;
    }

    public function setElapsedWashTimeSecondsForTest(int $seconds): void
    {
        $this->elapsedWashTimeSeconds = $seconds;
    }

    public function setIncludedMinutesForTest(int $minutes): void
    {
        $this->includedMinutes = $minutes;
    }

    public function setDraftCustomerNumberForTest(?int $customer_number): void
    {
        $this->draftCustomerNumber = $customer_number;
    }

    public function getLaneStatus(): selfserve_lane_status
    {
        return $this->laneStatus;
    }

    public function getLaneMode(): selfserve_lane_mode
    {
        return $this->laneMode;
    }

    public function getCustomerNumber(): int
    {
        return $this->customerNumber;
    }

    public function getLicensePlate(): string
    {
        return $this->licensePlate;
    }

    public function getMinuteBillingProductId(): ?int
    {
        return $this->minuteBillingProductId;
    }

    public function getElapsedWashTime(): ?int
    {
        return $this->elapsedWashTimeSeconds;
    }

    public function getMachineWashMinutesIncluded(): int
    {
        return $this->includedMinutes;
    }

    protected function createInvoiceOrderContext(): orders_o
    {
        $this->createdOrderContexts++;
        $billing_customer_number = $this->getCustomerNumber();
        $draft_customer_number = $this->draftCustomerNumber;
        $order = new SelfserveLaneInvoiceModeOrderStub();
        $order->id = 424242;
        $this->lastOrderCustomerNumber = $billing_customer_number;
        $this->last_invoice_order_id = (int)$order->id;
        $this->attachSelfServeMetadataToOrder($order, $billing_customer_number, $draft_customer_number);
        return $order;
    }

    protected function attachSelfServeMetadataToOrder(
        orders_o $order,
        int $billing_customer_number,
        ?int $draft_customer_number,
        ?\modules\selfserve\classes\selfserve_lane_command_arguments $arguments = null
    ): void {
        $order->attachedBillingCustomerNumber = $billing_customer_number;
        $order->attachedDraftCustomerNumber = $draft_customer_number;
        $this->lastAttachmentBillingCustomerNumber = $billing_customer_number;
        $this->lastAttachmentDraftCustomerNumber = $draft_customer_number;
    }

    protected function addMinuteBillingLine(int $order_id, int $product_id, int $quantity): void
    {
        $this->lastAddedOrderId = $order_id;
        $this->lastAddedProductId = $product_id;
        $this->lastAddedQuantity = $quantity;
    }
}

it('bills manual self-serve stop using full elapsed minutes without included-minute reduction', function (): void {
    $harness = new SelfserveLaneInvoiceModeBillingHarness();
    $harness->setLaneModeForTest(selfserve_lane_mode::MANUAL);
    $harness->setElapsedWashTimeSecondsForTest(59);
    $harness->setIncludedMinutesForTest(5);

    $result = $harness->invoice();

    expect($result)->toBeTrue();
    expect($harness->lastAddedOrderId)->toBe(424242);
    expect($harness->lastAddedProductId)->toBe(999);
    expect($harness->lastAddedQuantity)->toBe(1);
    expect($harness->createdOrderContexts)->toBe(1);
    expect($harness->getLastInvoiceOrderId())->toBe(424242);
});

it('keeps included-minute reduction for automatic mode', function (): void {
    $harness = new SelfserveLaneInvoiceModeBillingHarness();
    $harness->setLaneModeForTest(selfserve_lane_mode::AUTOMATIC);
    $harness->setElapsedWashTimeSecondsForTest(59);
    $harness->setIncludedMinutesForTest(5);

    $result = $harness->invoice();

    expect($result)->toBeTrue();
    expect($harness->lastAddedOrderId)->toBeNull();
    expect($harness->lastAddedProductId)->toBeNull();
    expect($harness->lastAddedQuantity)->toBeNull();
    expect($harness->createdOrderContexts)->toBe(0);
    expect($harness->getLastInvoiceOrderId())->toBeNull();
});

it('creates self-serve invoice orders for the actual lane customer when a draft customer is configured', function (): void {
    $harness = new SelfserveLaneInvoiceModeBillingHarness();
    $harness->setLaneModeForTest(selfserve_lane_mode::MANUAL);
    $harness->setElapsedWashTimeSecondsForTest(59);
    $harness->setDraftCustomerNumberForTest(9999);

    $result = $harness->invoice();

    expect($result)->toBeTrue();
    expect($harness->createdOrderContexts)->toBe(1);
    expect($harness->lastOrderCustomerNumber)->toBe(1234);
    expect($harness->lastAttachmentBillingCustomerNumber)->toBe(1234);
    expect($harness->lastAttachmentDraftCustomerNumber)->toBe(9999);
});

it('keeps the real billing customer as the authoritative order customer in the invoice context', function (): void {
    $source = file_get_contents(app_path('modules/selfserve/traits/selfserve_lane_invoice_t.php'));

    expect($source)->not->toContain('$order_customer_number = $draft_customer_number ?? $billing_customer_number');
    expect($source)->toContain('(new orders_o())->add(
            $billing_customer_number,');
    expect($source)->toContain('$this->attachSelfServeMetadataToOrder($order, $billing_customer_number, $draft_customer_number, $arguments);');
});
