<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\Warehouse;
use App\Models\WarehouseAddress;
use App\Support\CrmModuleManager;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class WarehouseController extends Controller
{
    public function __construct()
    {
        $this->authorizeResource(Warehouse::class, 'warehouse');
    }

    public function index(Request $request): View
    {
        $search = trim((string) $request->input('q', ''));
        $status = trim((string) $request->input('status', ''));

        $warehouses = Warehouse::query()
            ->with('manager')
            ->when($search !== '', function ($query) use ($search): void {
                $query->where(function ($sub) use ($search): void {
                    $sub->where('name', 'like', "%{$search}%")
                        ->orWhere('code', 'like', "%{$search}%")
                        ->orWhere('location', 'like', "%{$search}%")
                        ->orWhere('description', 'like', "%{$search}%");
                });
            })
            ->when(in_array($status, ['active', 'inactive'], true), fn ($query) => $query->where('status', $status))
            ->latest('id')
            ->paginate(20)
            ->withQueryString();

        return view('warehouses.index', [
            'warehouses' => $warehouses,
            'search' => $search,
            'status' => $status,
            'statusOptions' => $this->statusOptions(),
        ]);
    }

    public function create(): View
    {
        return view('warehouses.create', [
            'managers' => User::query()->orderBy('name')->get(),
            'statusOptions' => $this->statusOptions(),
        ]);
    }

    public function store(Request $request, CrmModuleManager $moduleManager): RedirectResponse
    {
        $payload = $this->validatedData($request);
        $payload = $moduleManager->applyPayloadHooks('warehouses.store', $payload, [
            'hook' => 'warehouses.store',
            'user_id' => $request->user()->id,
        ], array_keys($payload));

        $warehouse = Warehouse::create($payload);

        return redirect()
            ->route('warehouses.show', $warehouse)
            ->with('success', __('Warehouse has been created.'));
    }

    public function show(Warehouse $warehouse): View
    {
        $warehouse->load([
            'manager',
            'addresses' => fn ($query) => $query->orderBy('y')->orderBy('x')->orderBy('id'),
        ]);

        return view('warehouses.show', [
            'warehouse' => $warehouse,
            'addressStatuses' => $this->addressStatusOptions(),
            'addressLookup' => $warehouse->addresses->keyBy(
                static fn (WarehouseAddress $address): string => $address->x.'-'.$address->y
            ),
        ]);
    }

    public function edit(Warehouse $warehouse): View
    {
        return view('warehouses.edit', [
            'warehouse' => $warehouse,
            'managers' => User::query()->orderBy('name')->get(),
            'statusOptions' => $this->statusOptions(),
        ]);
    }

    public function update(Request $request, Warehouse $warehouse, CrmModuleManager $moduleManager): RedirectResponse
    {
        $payload = $this->validatedData($request, $warehouse);
        $payload = $moduleManager->applyPayloadHooks('warehouses.update', $payload, [
            'hook' => 'warehouses.update',
            'user_id' => $request->user()->id,
            'warehouse_id' => $warehouse->id,
        ], array_keys($payload));

        $warehouse->update($payload);

        return redirect()
            ->route('warehouses.show', $warehouse)
            ->with('success', __('Warehouse has been updated.'));
    }

    public function updateMap(Request $request, Warehouse $warehouse, CrmModuleManager $moduleManager): RedirectResponse
    {
        $this->authorize('update', $warehouse);

        $payload = $request->validate([
            'map_rows' => ['required', 'integer', 'min:1', 'max:200'],
            'map_columns' => ['required', 'integer', 'min:1', 'max:200'],
        ]);

        $payload['map_rows'] = (int) $payload['map_rows'];
        $payload['map_columns'] = (int) $payload['map_columns'];
        $payload = $moduleManager->applyPayloadHooks('warehouses.map.update', $payload, [
            'hook' => 'warehouses.map.update',
            'warehouse_id' => $warehouse->id,
            'user_id' => $request->user()->id,
        ], ['map_rows', 'map_columns']);

        $warehouse->update($payload);

        return redirect()
            ->route('warehouses.show', $warehouse)
            ->with('success', __('Warehouse map settings have been updated.'));
    }

    public function destroy(Warehouse $warehouse): RedirectResponse
    {
        $warehouse->delete();

        return redirect()
            ->route('warehouses.index')
            ->with('success', __('Warehouse has been deleted.'));
    }

    /**
     * @return array<string, mixed>
     */
    private function validatedData(Request $request, ?Warehouse $warehouse = null): array
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'code' => [
                'nullable',
                'string',
                'max:100',
                Rule::unique('warehouses', 'code')->ignore($warehouse?->id),
            ],
            'location' => ['nullable', 'string', 'max:255'],
            'capacity' => ['nullable', 'numeric', 'min:0'],
            'status' => ['required', Rule::in(['active', 'inactive'])],
            'manager_id' => ['nullable', 'exists:users,id'],
            'description' => ['nullable', 'string'],
            'map_rows' => ['nullable', 'integer', 'min:1', 'max:200'],
            'map_columns' => ['nullable', 'integer', 'min:1', 'max:200'],
        ]);

        $validated['capacity'] = (float) ($validated['capacity'] ?? 0);
        $validated['map_rows'] = (int) ($validated['map_rows'] ?? ($warehouse?->map_rows ?? 8));
        $validated['map_columns'] = (int) ($validated['map_columns'] ?? ($warehouse?->map_columns ?? 12));

        return $validated;
    }

    /**
     * @return array<string, string>
     */
    private function statusOptions(): array
    {
        return [
            'active' => __('Active'),
            'inactive' => __('Inactive'),
        ];
    }

    /**
     * @return array<string, string>
     */
    private function addressStatusOptions(): array
    {
        return [
            'free' => __('Free'),
            'reserved' => __('Reserved'),
            'blocked' => __('Blocked'),
        ];
    }
}
