<?php

namespace App\Http\Controllers\Franchise;

use App\Http\Controllers\Controller;
use App\Models\Franchise;
use App\Models\FranchiseStockRequest;
use App\Models\FranchiseStockRequestItem;
use App\Models\Product;
use App\Models\Warehouse;
use App\Services\FranchiseNotificationService;
use App\Services\FranchiseStockService;
use App\Services\WarehouseDistributionService;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class StockRequestController extends Controller
{
    public function index(): View
    {
        $franchise = Franchise::query()->where('created_by', auth()->id())->first();
        $requests = FranchiseStockRequest::query()
            ->where('franchise_id', $franchise?->id)
            ->latest('id')
            ->with(['items.product', 'requestedWarehouse'])
            ->paginate(15);

        $products = Product::query()->where('is_active', true)->orderBy('name')->get();
        $warehouses = Warehouse::query()->where('is_active', true)->orderBy('name')->get();

        return view('franchise.stock-requests', compact('franchise', 'requests', 'products', 'warehouses'));
    }

    public function store(Request $request, FranchiseNotificationService $notificationService): RedirectResponse
    {
        $validated = $request->validate([
            'product_id' => ['required', 'array'],
            'product_id.*' => ['required', 'exists:products,id'],
            'quantity' => ['required', 'array'],
            'quantity.*' => ['required', 'numeric', 'min:0.01'],
            'requested_warehouse_id' => ['nullable', 'exists:warehouses,id'],
            'notes' => ['nullable', 'string', 'max:500'],
        ]);

        $franchise = Franchise::query()->where('created_by', auth()->id())->first();
        if (! $franchise) {
            return back()->withErrors(['franchise' => 'Franchise not found.']);
        }

        $requestNo = 'REQ'.Str::upper(Str::random(8));
        $stockRequest = FranchiseStockRequest::query()->create([
            'franchise_id' => $franchise->id,
            'requested_warehouse_id' => $validated['requested_warehouse_id'] ?? null,
            'request_number' => $requestNo,
            'status' => 'pending',
            'requested_at' => now(),
            'notes' => $validated['notes'] ?? null,
        ]);

        foreach ($validated['product_id'] as $index => $productId) {
            FranchiseStockRequestItem::query()->create([
                'request_id' => $stockRequest->id,
                'product_id' => (int) $productId,
                'quantity_requested' => (float) ($validated['quantity'][$index] ?? 0),
                'quantity_delivered' => 0,
            ]);
        }

        $notificationService->notify(
            $franchise,
            'Stock Request Submitted',
            "Stock request {$stockRequest->request_number} created and pending admin approval.",
            route('franchise.stock-requests')
        );

        return back()->with('status', 'Stock request submitted.');
    }

    public function confirmDelivered(
        int $requestId,
        FranchiseStockService $stockService,
        FranchiseNotificationService $notificationService,
        WarehouseDistributionService $distributionService
    ): RedirectResponse
    {
        $franchise = Franchise::query()->where('created_by', auth()->id())->first();
        $stockRequest = FranchiseStockRequest::query()->where('franchise_id', $franchise?->id)->whereKey($requestId)->with('items.product')->first();
        if (! $stockRequest) {
            return back()->withErrors(['request' => 'Request not found.']);
        }
        if ($stockRequest->status === 'delivered') {
            return back()->withErrors(['request' => 'Request already delivered.']);
        }

        $items = [];
        foreach ($stockRequest->items as $item) {
            $items[] = [
                'product_id' => $item->product_id,
                'quantity' => (float) $item->quantity_requested,
                'unit_price' => (float) ($item->product?->dp_price ?? 0),
                'unit_bv' => (float) ($item->product?->bv ?? 0),
            ];
        }

        try {
            DB::transaction(function () use ($stockRequest, $items, $franchise, $distributionService, $stockService): void {
                $stockRequest->status = 'delivered';
                $stockRequest->delivered_at = now();
                $stockRequest->save();

                foreach ($stockRequest->items as $item) {
                    $item->quantity_delivered = $item->quantity_requested;
                    $item->save();
                }

                if ($stockRequest->requested_warehouse_id) {
                    foreach ($items as $item) {
                        $distributionService->dispatchToFranchise(
                            (int) $stockRequest->requested_warehouse_id,
                            (int) $franchise->id,
                            (int) $item['product_id'],
                            (float) $item['quantity'],
                            (float) $item['unit_price'],
                            (float) $item['unit_bv'],
                            [
                                'reference' => $stockRequest->request_number,
                                'created_by' => auth()->id(),
                                'narration' => 'Dispatched from warehouse',
                            ]
                        );
                    }
                } else {
                    $stockService->receiveStockRequest($franchise->id, $items, [
                        'reference' => $stockRequest->request_number,
                        'created_by' => auth()->id(),
                    ]);
                }
            });
        } catch (\RuntimeException $exception) {
            return back()->withErrors(['request' => $exception->getMessage()]);
        }

        $notificationService->notify(
            $franchise,
            'Stock Request Delivered',
            "Stock request {$stockRequest->request_number} has been marked delivered and inventory updated.",
            route('franchise.stock')
        );

        return back()->with('status', 'Stock marked as delivered and added to inventory.');
    }
}

