<?php

namespace App\Modules\Procurement\Controllers;

use App\Http\Controllers\Controller;
use App\Modules\Procurement\Exceptions\ReceivingOperationalException;
use App\Modules\Procurement\Models\GoodsReceipt;
use App\Modules\Procurement\Models\PurchaseOrder;
use App\Modules\Procurement\Requests\PostGoodsReceiptRequest;
use App\Modules\Procurement\Requests\StoreGoodsReceiptRequest;
use App\Modules\Procurement\Services\GoodsReceiptDraftWithLinesService;
use App\Modules\Procurement\Services\GoodsReceiptLifecycleService;
use App\Modules\Procurement\Services\GoodsReceiptPostingService;
use App\Modules\Procurement\Services\ProcurementOperationalUiFailureRecorder;
use App\Modules\Procurement\Services\PurchaseOrderLifecycleService;
use Illuminate\Http\RedirectResponse;

class GoodsReceiptWorkflowController extends Controller
{
    public function __construct(
        private readonly PurchaseOrderLifecycleService $purchaseOrders,
        private readonly GoodsReceiptDraftWithLinesService $draftWithLines,
        private readonly GoodsReceiptLifecycleService $receiptLifecycle,
        private readonly GoodsReceiptPostingService $posting,
        private readonly ProcurementOperationalUiFailureRecorder $uiFailures,
    ) {}

    public function store(StoreGoodsReceiptRequest $request, PurchaseOrder $purchaseOrder): RedirectResponse
    {
        $this->authorize('createReceipt', $purchaseOrder);
        $user = $request->user();
        $tenantId = (int) $user->tenant_id;

        try {
            $this->purchaseOrders->assertPurchaseOrderAllowsReceiving($purchaseOrder);
            $receipt = $this->draftWithLines->createForPurchaseOrder(
                $tenantId,
                (int) $purchaseOrder->id,
                (int) $request->validated('warehouse_id'),
            );
        } catch (ReceivingOperationalException $e) {
            $this->uiFailures->recordDraftCreationFailure($tenantId, (int) $purchaseOrder->id, $e);

            return redirect()
                ->back()
                ->withErrors(['operational' => $e->getMessage()]);
        }

        return redirect()
            ->route('procurement.goods-receipts.show', $receipt)
            ->with('status', __('procurement.receipts.flash.created'));
    }

    public function submitValidation(GoodsReceipt $goodsReceipt): RedirectResponse
    {
        $this->authorize('transition', $goodsReceipt);
        $tenantId = (int) auth()->user()?->tenant_id;
        abort_if($tenantId === 0, 403);

        try {
            $this->receiptLifecycle->markValidated($tenantId, (int) $goodsReceipt->id);
        } catch (ReceivingOperationalException $e) {
            $this->uiFailures->recordFromReceivingException($tenantId, $goodsReceipt, $e, 'validate');

            return redirect()
                ->route('procurement.goods-receipts.show', $goodsReceipt)
                ->withErrors(['operational' => $e->getMessage()]);
        }

        return redirect()
            ->route('procurement.goods-receipts.show', $goodsReceipt)
            ->with('status', __('procurement.receipts.flash.validated'));
    }

    public function submitPosting(PostGoodsReceiptRequest $request, GoodsReceipt $goodsReceipt): RedirectResponse
    {
        $this->authorize('transition', $goodsReceipt);
        $user = $request->user();
        $tenantId = (int) $user->tenant_id;
        abort_if($tenantId === 0, 403);

        try {
            $this->posting->postValidatedReceipt(
                $tenantId,
                (int) $goodsReceipt->id,
                (string) $request->validated('idempotency_key'),
                'web_ui',
                $user->id,
                null,
            );
        } catch (ReceivingOperationalException $e) {
            $this->uiFailures->recordFromReceivingException($tenantId, $goodsReceipt, $e, 'post');

            return redirect()
                ->route('procurement.goods-receipts.show', $goodsReceipt)
                ->withErrors(['operational' => $e->getMessage()]);
        }

        return redirect()
            ->route('procurement.goods-receipts.show', $goodsReceipt)
            ->with('status', __('procurement.receipts.flash.posted'));
    }
}
