<?php

namespace App\Http\Controllers\Admin;

use App\CentralLogics\Helpers;
use App\Exceptions\OrderFinancialException;
use App\Http\Controllers\Controller;
use App\Models\Item;
use App\Models\Order;
use App\Models\OrderExchange;
use App\Models\OrderReceipt;
use App\Services\OrderFinancialService;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Http\Request;

class OrderFinancialController extends Controller
{
    public function __construct(private readonly OrderFinancialService $financialService)
    {
    }

    public function recordAdvance(Order $order, Request $request)
    {
        $this->authorizeOrderModule();

        $validated = $request->validate([
            'idempotency_key' => ['required', 'uuid'],
            'amount' => ['required', 'numeric', 'gt:0'],
            'payment_method' => ['required', 'string', 'max:100'],
            'transaction_ref' => ['nullable', 'string', 'max:120'],
            'notes' => ['nullable', 'string', 'max:1000'],
        ]);

        try {
            $receipt = $this->financialService->recordAdvance($order, $validated, auth('admin')->id());
            Toastr::success('Advance received. Receipt '.$receipt->voucher_no.' has been posted.');
        } catch (OrderFinancialException $exception) {
            Toastr::error($exception->getMessage());
        } catch (\Throwable $throwable) {
            report($throwable);
            Toastr::error('Advance receipt could not be posted. Please try again.');
        }

        return back();
    }

    public function voidReceipt(OrderReceipt $receipt, Request $request)
    {
        $this->authorizeOrderModule();
        $validated = $request->validate(['reason' => ['nullable', 'string', 'max:500']]);

        try {
            $this->financialService->voidReceipt($receipt, auth('admin')->id(), $validated['reason'] ?? null);
            Toastr::success('Receipt has been voided and the order due has been recalculated.');
        } catch (OrderFinancialException $exception) {
            Toastr::error($exception->getMessage());
        } catch (\Throwable $throwable) {
            report($throwable);
            Toastr::error('Receipt could not be voided. Please try again.');
        }

        return back();
    }

    public function receiptVoucher(OrderReceipt $receipt)
    {
        $this->authorizeOrderModule();
        $receipt->load(['order.store', 'order.customer', 'customer', 'account', 'createdByAdmin']);

        return view('admin-views.order.receipt-voucher', compact('receipt'));
    }

    public function recordExchange(Order $order, Request $request)
    {
        $this->authorizeOrderModule();

        $validated = $request->validate([
            'idempotency_key' => ['required', 'uuid'],
            'order_detail_id' => ['required', 'integer'],
            'return_quantity' => ['required', 'integer', 'min:1'],
            'replacement_item_id' => ['required', 'integer'],
            'replacement_quantity' => ['required', 'integer', 'min:1'],
            'replacement_unit_price' => ['required', 'numeric', 'min:0'],
            'notes' => ['nullable', 'string', 'max:1000'],
        ]);

        try {
            $exchange = $this->financialService->recordExchange($order, $validated, auth('admin')->id());
            Toastr::success('Product exchange '.$exchange->exchange_no.' has been posted.');
        } catch (OrderFinancialException $exception) {
            Toastr::error($exception->getMessage());
        } catch (\Throwable $throwable) {
            report($throwable);
            Toastr::error('Product exchange could not be posted. Please try again.');
        }

        return back();
    }

    public function voidExchange(OrderExchange $exchange, Request $request)
    {
        $this->authorizeOrderModule();
        $validated = $request->validate(['reason' => ['nullable', 'string', 'max:500']]);

        try {
            $this->financialService->voidExchange($exchange, auth('admin')->id(), $validated['reason'] ?? null);
            Toastr::success('Exchange has been voided and all amounts have been recalculated.');
        } catch (OrderFinancialException $exception) {
            Toastr::error($exception->getMessage());
        } catch (\Throwable $throwable) {
            report($throwable);
            Toastr::error('Exchange could not be voided. Please try again.');
        }

        return back();
    }

    public function replacementItems(Order $order, Request $request)
    {
        $this->authorizeOrderModule();
        $search = trim((string) $request->query('q'));

        $items = Item::withoutGlobalScopes()
            ->where('store_id', $order->store_id)
            ->when($search, fn ($query) => $query->where('name', 'like', '%'.$search.'%'))
            ->orderBy('name')
            ->limit(20)
            ->get(['id', 'name', 'price']);

        return response()->json([
            'results' => $items->map(fn (Item $item) => [
                'id' => $item->id,
                'text' => $item->name.' (#'.$item->id.')',
                'price' => (float) $item->price,
            ])->values(),
        ]);
    }

    private function authorizeOrderModule(): void
    {
        abort_unless(Helpers::module_permission_check('order'), 403);
    }
}
