<?php

namespace App\Support\Invoice;

use App\Services\InvoiceService;

/**
 * The worst-case invoice the live preview renders: every feature this schema
 * supports, on one document, so a landlord sees whether their letterhead
 * survives a genuinely hostile bill rather than a two-line happy path.
 *
 * What it deliberately exercises:
 *  - eight lines including a long wrapping description and a fractional qty
 *  - mixed VAT rates (18%, 8%, 0%) so the tax summary has to group
 *  - both discount styles on lines: percentage and fixed
 *  - a line whose 100% discount makes it a free/complimentary item
 *  - a bundle exploded into components sharing a group key
 *  - a serialised line and a batch-tracked line with expiry
 *  - packaging/add-on products, which are ordinary lines like any other
 *  - three discount sources: voucher, loyalty redemption, manual header
 *  - split tenders including a PENDING cheque that does not reduce the balance
 *  - a part-paid invoice, so a balance is outstanding
 *
 * The arithmetic mirrors {@see InvoiceService::create()} exactly,
 * including the asymmetry that VAT is charged on the post-line-discount total
 * but is NOT reduced by invoice-level discounting.
 */
final class SampleInvoice
{
    public static function build(InvoiceBusiness $business, string $currencySymbol = 'Rs.'): InvoiceDocument
    {
        $lines = self::lines();

        $grossSubtotal = 0.0;
        $lineDiscountTotal = 0.0;
        $vatTotal = 0.0;

        foreach ($lines as $line) {
            $grossSubtotal += $line->grossTotal;
            $lineDiscountTotal += $line->discountAmount;
            $vatTotal += $line->vatAmount;
        }

        // Invoice-level discounting, applied to the discounted-plus-VAT base.
        $discountBreakdown = [
            ['label' => 'Voucher NEWYEAR25', 'amount' => 1500.00],
            ['label' => 'Loyalty points redeemed (2,400 pts)', 'amount' => 240.00],
            ['label' => 'Invoice discount', 'amount' => 750.00],
        ];

        $invoiceDiscountTotal = 0.0;
        foreach ($discountBreakdown as $row) {
            $invoiceDiscountTotal += $row['amount'];
        }

        $netSubtotal = round($grossSubtotal - $lineDiscountTotal, 2);
        $vatTotal = round($vatTotal, 2);

        $netTotal = max(0, round($netSubtotal - $invoiceDiscountTotal + $vatTotal, 2));

        $payments = [
            ['method' => 'Cash', 'reference' => null, 'amount' => 20000.00, 'status' => 'Approved', 'pending' => false],
            ['method' => 'Card', 'reference' => 'VISA ****4192 · auth 8830QK', 'amount' => 15000.00, 'status' => 'Approved', 'pending' => false],
            ['method' => 'Cheque', 'reference' => 'Cheque 004417 · Sampath Bank', 'amount' => 10000.00, 'status' => 'Pending', 'pending' => true],
        ];

        // Only cleared tenders reduce the balance — the pending cheque is shown
        // but excluded, exactly as PaymentService::recomputeInvoicePayment() does.
        $paidAmount = 0.0;
        foreach ($payments as $payment) {
            if (! $payment['pending']) {
                $paidAmount += $payment['amount'];
            }
        }

        $paidAmount = round(min($paidAmount, $netTotal), 2);

        return new InvoiceDocument(
            business: $business,
            number: 'INV-2026-004182',
            physicalReference: 'BK-14/0291',
            issuedAt: now()->format('d M Y, H:i'),
            customer: [
                'name' => 'Ranaweera Motors & Hardware Supplies (Pvt) Ltd',
                'phone' => '077 418 2260',
                'email' => 'accounts@ranaweeramotors.lk',
                'nic' => '199014302617',
                'address' => 'No 118/4A, Kandy Road, Katugastota, Kandy',
                'deliveryAddress' => 'Site store — Digana Industrial Estate, Unit 7',
                'isRegistered' => true,
            ],
            meta: [
                'branch' => 'Badulla Main',
                'channel' => 'till',
                'till' => 'Counter 02',
                'rep' => 'M. Fernando',
            ],
            lines: $lines,
            vatBreakdown: self::vatBreakdown($lines),
            discountBreakdown: $discountBreakdown,
            payments: $payments,
            grossSubtotal: round($grossSubtotal, 2),
            lineDiscountTotal: round($lineDiscountTotal, 2),
            invoiceDiscountTotal: round($invoiceDiscountTotal, 2),
            vatTotal: $vatTotal,
            netTotal: $netTotal,
            paidAmount: $paidAmount,
            balance: round($netTotal - $paidAmount, 2),
            tenderedAmount: null,
            changeAmount: null,
            currencySymbol: $currencySymbol,
            note: 'Goods remain the property of the seller until paid in full. None of the items are refundable except damaged items. Warranty claims require this invoice.',
            isSample: true,
            paymentStatus: 'Partial',
            orderStatus: 'Completed',
            amendedFrom: 'INV-2026-004108',
        );
    }

    /** @return list<InvoiceDocumentLine> */
    private static function lines(): array
    {
        return [
            self::line(
                name: 'Bosch S4 Silver 12V 74Ah Maintenance-Free Automotive Battery with 3-Year Replacement Warranty',
                sku: 'BAT-BSH-S4-074',
                quantity: 2,
                unit: 'EACH',
                unitPrice: 28500.00,
                vatRate: 18.0,
                discountType: 'percentage',
                discountValue: 7.5,
                serialNumber: 'BSH74-2026-0041827',
            ),
            self::line(
                name: 'Castrol GTX 20W-50 Engine Oil',
                sku: 'OIL-CTL-GTX-4L',
                quantity: 3,
                unit: 'BOX',
                unitPrice: 9450.00,
                vatRate: 18.0,
                discountType: 'fixed',
                discountValue: 2000.00,
                batchNumber: 'CTL-B2291',
                batchExpiry: '14 Mar 2028',
            ),
            self::line(
                name: 'Front Brake Pad Set — ceramic',
                sku: 'BRK-PAD-CER-11',
                quantity: 4,
                unit: 'SET',
                unitPrice: 6800.00,
                vatRate: 18.0,
            ),
            self::line(
                name: 'Radiator Coolant Concentrate',
                sku: 'CLT-GRN-005',
                quantity: 2.5,
                unit: 'LTR',
                unitPrice: 2240.00,
                vatRate: 8.0,
            ),
            self::line(
                name: 'Service Kit — Filters & Plugs',
                sku: 'BND-SVC-KIT-A',
                quantity: 1,
                unit: 'SET',
                unitPrice: 7900.00,
                vatRate: 18.0,
                bundleName: 'Full Service Bundle',
                bundleGroupKey: 'BND1',
            ),
            self::line(
                name: 'Wiper Blade Pair 22"',
                sku: 'WPR-22-PR',
                quantity: 1,
                unit: 'PAIR',
                unitPrice: 3100.00,
                vatRate: 18.0,
                bundleName: 'Full Service Bundle',
                bundleGroupKey: 'BND1',
            ),
            self::line(
                name: 'Workshop Labour — 1.5 hours',
                sku: 'LAB-WRK-STD',
                quantity: 1.5,
                unit: 'MTR',
                unitPrice: 3500.00,
                vatRate: 0.0,
            ),
            self::line(
                name: 'Microfibre Cloth (complimentary)',
                sku: 'ACC-MF-CLTH',
                quantity: 1,
                unit: 'EACH',
                unitPrice: 850.00,
                vatRate: 18.0,
                discountType: 'percentage',
                discountValue: 100.0,
            ),
            // Packaging/add-ons are ordinary products sitting under the
            // "Packaging & Add-ons" system category — nothing about the
            // printed line distinguishes them.
            self::line(
                name: 'Heavy-duty crate packaging',
                sku: 'PKG-OTHR-001',
                quantity: 1,
                unit: 'EACH',
                unitPrice: 1250.00,
                vatRate: 18.0,
            ),
            self::line(
                name: 'Pallet wrap & strapping',
                sku: 'PKG-OTHR-002',
                quantity: 2,
                unit: 'EACH',
                unitPrice: 320.00,
                vatRate: 0.0,
            ),
        ];
    }

    /**
     * Builds a line the same way InvoiceService does: the discount is clamped
     * to the gross, and VAT is charged on what is left.
     */
    private static function line(
        string $name,
        string $sku,
        float $quantity,
        string $unit,
        float $unitPrice,
        float $vatRate,
        ?string $discountType = null,
        float $discountValue = 0.0,
        ?string $serialNumber = null,
        ?string $batchNumber = null,
        ?string $batchExpiry = null,
        ?string $bundleName = null,
        ?string $bundleGroupKey = null,
    ): InvoiceDocumentLine {
        $grossTotal = round($quantity * $unitPrice, 2);

        $discountAmount = match ($discountType) {
            'percentage' => round($grossTotal * ($discountValue / 100), 2),
            'fixed' => round($discountValue * $quantity, 2),
            default => 0.0,
        };

        $discountAmount = round(min(max($discountAmount, 0), $grossTotal), 2);
        $lineTotal = round($grossTotal - $discountAmount, 2);

        return new InvoiceDocumentLine(
            name: $name,
            sku: $sku,
            quantity: $quantity,
            unit: $unit,
            unitPrice: $unitPrice,
            grossTotal: $grossTotal,
            discountType: $discountType,
            discountValue: $discountValue,
            discountAmount: $discountAmount,
            lineTotal: $lineTotal,
            vatRate: $vatRate,
            vatAmount: round($lineTotal * $vatRate / 100, 2),
            serialNumber: $serialNumber,
            batchNumber: $batchNumber,
            batchExpiry: $batchExpiry,
            bundleName: $bundleName,
            bundleGroupKey: $bundleGroupKey,
        );
    }

    /**
     * @param  list<InvoiceDocumentLine>  $lines
     * @return list<array{rate: float, base: float, vat: float}>
     */
    private static function vatBreakdown(array $lines): array
    {
        $groups = [];

        foreach ($lines as $line) {
            $key = number_format($line->vatRate, 2, '.', '');
            $groups[$key] ??= ['rate' => $line->vatRate, 'base' => 0.0, 'vat' => 0.0];
            $groups[$key]['base'] += $line->lineTotal;
            $groups[$key]['vat'] += $line->vatAmount;
        }

        $groups = array_values(array_map(fn (array $g): array => [
            'rate' => $g['rate'],
            'base' => round($g['base'], 2),
            'vat' => round($g['vat'], 2),
        ], $groups));

        usort($groups, fn (array $a, array $b): int => $a['rate'] <=> $b['rate']);

        return $groups;
    }
}
