<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreManualAdjustmentRequest;
use App\Models\Product;
use App\Models\StockAdjustment;
use App\Models\StockMovement;
use App\Models\VariantStockMovement;
use App\Services\LocationInventoryService;
use App\Services\LocationService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;

class StockAdjustmentController extends Controller
{
    public function __construct(
        protected LocationInventoryService $locationInventory,
        protected LocationService $locationService,
    ) {
    }

    public function manual(): View
    {
        $this->authorize('stock-adjustments.manage');
        $reasonOptions = StoreManualAdjustmentRequest::reasonOptions();
        $locations = $this->locationService->accessibleLocations(auth()->user());
        $useLocationInventory = $this->locationInventory->useLocationInventory();
        return view('admin.stock-adjustments.manual', compact('reasonOptions', 'locations', 'useLocationInventory'));
    }

    public function storeManual(StoreManualAdjustmentRequest $request): RedirectResponse
    {
        $this->authorize('stock-adjustments.manage');
        $data = $request->validated();
        $productId = $data['variant_id'] ?? $data['product_id'];
        $product = Product::findOrFail($productId);
        $quantity = (float) $data['quantity'];
        $locationId = isset($data['location_id']) ? (int) $data['location_id'] : null;

        try {
            DB::transaction(function () use ($data, $product, $productId, $quantity, $locationId) {
                if ($this->locationInventory->useLocationInventory()) {
                    if (!$locationId) {
                        throw new \InvalidArgumentException('location_id is required when location inventory is enabled.');
                    }
                    $this->locationService->resolveAuthorizedLocationId(auth()->user(), $locationId);

                    $beforeQty = (float) $this->locationInventory->getOnHand((int) $productId, $locationId);
                    $afterQty = $data['adjustment_type'] === StockAdjustment::TYPE_ADDITION
                        ? $beforeQty + $quantity
                        : $beforeQty - $quantity;
                    $delta = (int) round($afterQty - $beforeQty);

                    StockAdjustment::create([
                        'product_id' => $data['product_id'],
                        'variant_id' => $data['variant_id'] ?? null,
                        'location_id' => $locationId,
                        'adjustment_type' => $data['adjustment_type'],
                        'before_qty' => $beforeQty,
                        'adjusted_qty' => abs($afterQty - $beforeQty),
                        'after_qty' => $afterQty,
                        'reason' => $data['reason'],
                        'remarks' => $data['remarks'],
                        'reference_type' => StockAdjustment::REFERENCE_MANUAL,
                        'reference_id' => null,
                        'created_by' => auth()->id(),
                    ]);

                    if ($delta !== 0) {
                        $this->locationInventory->adjust(
                            (int) $productId,
                            $delta,
                            $locationId,
                            $data['remarks'],
                            auth()->id()
                        );
                    }

                    return;
                }

                $beforeQty = (float) $product->current_stock;
                $afterQty = $data['adjustment_type'] === StockAdjustment::TYPE_ADDITION
                    ? $beforeQty + $quantity
                    : $beforeQty - $quantity;
                $delta = (int) round($afterQty - $beforeQty);

                StockAdjustment::create([
                    'product_id' => $data['product_id'],
                    'variant_id' => $data['variant_id'] ?? null,
                    'adjustment_type' => $data['adjustment_type'],
                    'before_qty' => $beforeQty,
                    'adjusted_qty' => abs($afterQty - $beforeQty),
                    'after_qty' => $afterQty,
                    'reason' => $data['reason'],
                    'remarks' => $data['remarks'],
                    'reference_type' => StockAdjustment::REFERENCE_MANUAL,
                    'reference_id' => null,
                    'created_by' => auth()->id(),
                ]);

                if ($delta !== 0) {
                    if ($data['variant_id'] ?? null) {
                        VariantStockMovement::create([
                            'product_id' => $data['variant_id'],
                            'type' => VariantStockMovement::TYPE_ADJUSTMENT,
                            'quantity' => $delta,
                            'notes' => $data['remarks'],
                            'created_by' => auth()->id(),
                        ]);
                    } else {
                        StockMovement::create([
                            'product_id' => $data['product_id'],
                            'type' => StockMovement::TYPE_ADJUSTMENT,
                            'quantity' => $delta,
                            'notes' => $data['remarks'],
                            'created_by' => auth()->id(),
                        ]);
                    }
                    $product->recalculateStock();
                }
            });
            return redirect()->route('admin.stock-adjustments.index')
                ->with('success', 'Manual adjustment applied.');
        } catch (\Exception $e) {
            return redirect()->back()->withInput()->with('error', $e->getMessage());
        }
    }

    public function index(): View
    {
        $this->authorize('stock-adjustments.view');
        $adjustments = StockAdjustment::with(['product', 'variant', 'creator'])
            ->latest()
            ->paginate(25);
        return view('admin.stock-adjustments.index', compact('adjustments'));
    }
}
