<?php

declare(strict_types=1);

namespace App\Support\Print\Documents;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Models\DberpPurchaseReceiptOrder;
use App\Models\DberpPurchaseReceiptOrderItem;
use App\Services\DberpPermissionService;
use App\Support\DberpNumberFormatter;
use App\Support\Print\Contracts\DberpDocumentPrintPresenter;
use App\Support\Print\DberpPrintViewSupport;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Carbon;

final class PurchaseReceiptPrintPresenter implements DberpDocumentPrintPresenter
{
    public const string DOCUMENT_KEY = 'purchase-receipt';

    public function __construct(
        private readonly DberpPermissionService $permissionService,
    ) {}

    public function documentKey(): string
    {
        return self::DOCUMENT_KEY;
    }

    public function userCanPrint(?Authenticatable $user): bool
    {
        return $this->permissionService->allows($user, DberpPermissionService::VIEW_PURCHASE_RECEIPT);
    }

    public function prepareViewData(int|string $recordId): array
    {
        $order = DberpPurchaseReceiptOrder::query()
            ->with([
                'supplier',
                'warehouse',
                'handlerEmployee',
                'purchaseOrder',
                'items' => fn ($query) => $query->orderBy('sort_order')->orderBy('id'),
            ])
            ->findOrFail($recordId);

        $status = InventoryDocumentStatus::tryFrom((string) $order->status);
        $statusLabel = $status?->label() ?? (string) $order->status;
        $showVoidWatermark = $status === InventoryDocumentStatus::Voided || $order->voided_at !== null;

        return [
            'view' => 'print.documents.purchase-receipt',
            'documentTitle' => (string) __('dberp.print.documents.purchase_receipt'),
            'statusLabel' => $statusLabel,
            'showVoidWatermark' => $showVoidWatermark,
            'printTime' => Carbon::now(),
            'company' => DberpPrintViewSupport::companyProfile(),
            'headerFields' => $this->headerFields($order, $statusLabel),
            'lines' => $order->items->values()->map(
                fn (DberpPurchaseReceiptOrderItem $item, int $index): array => $this->formatLine($item, $index + 1),
            ),
            'totals' => $this->totals($order),
            'signatures' => [
                (string) __('dberp.print.signatures.maker'),
                (string) __('dberp.print.signatures.receive'),
                (string) __('dberp.print.signatures.recheck'),
                (string) __('dberp.print.signatures.supplier_confirm'),
            ],
        ];
    }

    /**
     * @return list<array{label: string, value: string}>
     */
    private function headerFields(DberpPurchaseReceiptOrder $order, string $statusLabel): array
    {
        $fields = [
            [
                'label' => (string) __('dberp.fields.document_code'),
                'value' => (string) $order->code,
            ],
            [
                'label' => (string) __('dberp.fields.business_time'),
                'value' => $order->business_time?->format('Y-m-d H:i') ?? '—',
            ],
            [
                'label' => (string) __('dberp.print.labels.document_status'),
                'value' => $statusLabel,
            ],
            [
                'label' => (string) __('dberp.print.labels.supplier'),
                'value' => (string) ($order->supplier?->name ?? '—'),
            ],
            [
                'label' => (string) __('dberp.print.labels.warehouse'),
                'value' => (string) ($order->warehouse?->name ?? '—'),
            ],
        ];

        if ($order->arrival_date !== null) {
            $fields[] = [
                'label' => (string) __('dberp.fields.arrival_date'),
                'value' => $order->arrival_date->format('Y-m-d'),
            ];
        }

        $supplierContact = DberpPrintViewSupport::joinContactParts(
            (string) ($order->supplier_contact_person_snapshot ?? ''),
            (string) ($order->supplier_mobile_snapshot ?? ''),
            (string) ($order->supplier_phone_snapshot ?? ''),
        );
        if ($supplierContact !== '') {
            $fields[] = [
                'label' => (string) __('dberp.fields.contact_person'),
                'value' => $supplierContact,
            ];
        }

        $warehouseAddress = DberpPrintViewSupport::joinAddressParts(
            $order->warehouse_region_name_snapshot,
            $order->warehouse_address_snapshot,
        );
        if ($warehouseAddress !== '') {
            $fields[] = [
                'label' => (string) __('dberp.fields.address'),
                'value' => $warehouseAddress,
            ];
        }

        if ($order->handlerEmployee !== null) {
            $fields[] = [
                'label' => (string) __('dberp.fields.handler_employee'),
                'value' => (string) $order->handlerEmployee->name,
            ];
        }

        if (filled($order->delivery_note)) {
            $fields[] = [
                'label' => (string) __('dberp.fields.delivery_note'),
                'value' => (string) $order->delivery_note,
            ];
        }

        if (filled($order->remark)) {
            $fields[] = [
                'label' => (string) __('dberp.fields.remark'),
                'value' => (string) $order->remark,
            ];
        }

        return $fields;
    }

    /**
     * @return array{row_number: int, product_code: string, product_name: string, sku_spec: string, unit_name: string, quantity: string, unit_price: string, line_amount: string, batch_serial: string, remark: string}
     */
    private function formatLine(DberpPurchaseReceiptOrderItem $item, int $rowNumber): array
    {
        $quantity = (float) ($item->received_quantity ?? 0) > 0
            ? $item->received_quantity
            : $item->arrival_quantity;

        return [
            'row_number' => $rowNumber,
            'product_code' => (string) ($item->product_code ?? '—'),
            'product_name' => (string) ($item->product_name ?? '—'),
            'sku_spec' => DberpPrintViewSupport::formatSkuSpec($item->sku_code, $item->spec_text),
            'unit_name' => (string) ($item->unit_name ?? '—'),
            'quantity' => DberpNumberFormatter::quantity($quantity),
            'unit_price' => DberpNumberFormatter::money($item->unit_price),
            'line_amount' => DberpNumberFormatter::money($item->line_amount),
            'batch_serial' => DberpPrintViewSupport::formatBatchAndSerial($item->batch_no, $item->serial_numbers),
            'remark' => filled($item->remark) ? (string) $item->remark : '',
        ];
    }

    /**
     * @return list<array{label: string, value: string}>
     */
    private function totals(DberpPurchaseReceiptOrder $order): array
    {
        $totals = [];

        if ($order->total_received_quantity !== null) {
            $totals[] = [
                'label' => (string) __('dberp.fields.received_quantity'),
                'value' => DberpNumberFormatter::quantity($order->total_received_quantity),
            ];
        }

        if ($order->total_amount !== null) {
            $totals[] = [
                'label' => (string) __('dberp.fields.total_amount'),
                'value' => DberpNumberFormatter::money($order->total_amount),
            ];
        }

        return $totals;
    }
}
