<?php

namespace App\Livewire\Financial;

use App\Domain\Financial\Models\Expense;
use App\Domain\Financial\Services\ExpenseService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\ChecksTemporaryUploads;
use App\Domain\Shared\Traits\UsesBranchScope;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Title;
use Livewire\Component;
use Livewire\WithFileUploads;

#[Layout('layouts.app')]
#[Title('تفاصيل المصروف')]
class ExpenseShow extends Component
{
    use UsesBranchScope, WithFileUploads, ChecksTemporaryUploads;

    #[Locked]
    public string $uuid = '';

    public $receipt = null;
    public bool $showCancelModal = false;
    public bool $showRemoveModal = false;
    public string $cancellationReason = '';

    public function mount(string $uuid): void
    {
        $this->authorize('expenses.create');
        $this->uuid = $uuid;

        // Resolve once up front so an out-of-branch or unknown uuid fails on
        // the way in rather than on the way out.
        $this->expense();
    }

    /**
     * Re-read on every request instead of holding the model in component
     * state: the service mutates both the row and its journal, and a stale
     * copy would render a ledger that no longer exists.
     */
    private function expense(): Expense
    {
        $expense = Expense::with([
            'creator', 'canceller', 'attachmentUploader', 'branch',
            'transactions.debitAccount', 'transactions.creditAccount', 'transactions.creator',
        ])->where('uuid', $this->uuid)->firstOrFail();

        $branchId = $this->getActiveBranchId();

        abort_if($branchId && $expense->branch_id && $expense->branch_id !== $branchId, 403);

        return $expense;
    }

    public function rules(): array
    {
        return [
            // heic/heif are here because that is what an iPhone's camera roll
            // hands over: the picker accepted the photo and validation then
            // refused it, which read to the desk as "the upload is broken".
            'receipt' => 'required|file|max:' . config('uploads.max_kb') . '|mimes:jpg,jpeg,png,pdf,webp,heic,heif,gif,bmp',
        ];
    }

    public function messages(): array
    {
        return [
            'receipt.required' => 'اختر ملف الإيصال أولاً',
            'receipt.max' => __('حجم الملف لا يتجاوز :mb ميجابايت', ['mb' => intdiv((int) config('uploads.max_kb'), 1024)]),
            'receipt.mimes' => 'الملف يجب أن يكون صورة (jpg, png, webp, heic) أو PDF',
        ];
    }

    public function uploadReceipt(ExpenseService $service): void
    {
        $this->authorize('expenses.create');
        if (! $this->temporaryUploadIsUsable('receipt', $this->receipt)) {
            return;
        }

        $this->validate();

        try {
            // Read the metadata BEFORE storing. store() moves the file out of
            // livewire-tmp, and every getter after it goes back to a path that
            // no longer exists — getSize() threw Flysystem's
            // UnableToRetrieveMetadata and the desk got an error page on every
            // single receipt (1b62a44f-…, 2026-09-03). Array literals evaluate
            // in order, so 'path' first was the whole bug.
            $name = $this->receipt->getClientOriginalName();
            $mime = $this->receipt->getMimeType();
            $size = $this->receipt->getSize();

            $service->attachReceipt($this->expense(), [
                'path' => $this->receipt->store('expenses/receipts', 'local'),
                'name' => $name,
                'disk' => 'local',
                'mime' => $mime,
                'size' => $size,
            ], auth()->user());

            $this->receipt = null;
            session()->flash('success', __('تم إرفاق المستند بنجاح'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function removeReceipt(ExpenseService $service): void
    {
        $this->authorize('expenses.create');

        try {
            $service->removeReceipt($this->expense(), auth()->user());
            session()->flash('success', __('تم حذف المرفق'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }

        $this->showRemoveModal = false;
    }

    public function confirmCancel(ExpenseService $service): void
    {
        $this->authorize('expenses.create');

        $this->validate([
            'cancellationReason' => 'required|min:3|max:500',
        ], [
            'cancellationReason.required' => 'يرجى كتابة سبب الإلغاء',
            'cancellationReason.min' => 'السبب قصير جداً',
        ]);

        try {
            $service->cancelExpense($this->expense(), $this->cancellationReason, auth()->user());
            session()->flash('success', __('تم إلغاء المصروف بنجاح'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }

        $this->showCancelModal = false;
        $this->cancellationReason = '';
    }

    public function render()
    {
        return view('livewire.financial.expense-show', [
            'expense' => $this->expense(),
        ]);
    }
}
