<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Company;
use App\Models\Location;
use App\Services\LocationService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class LocationController extends Controller
{
    public function __construct(protected LocationService $locationService)
    {
        $this->middleware('auth');
    }

    public function index(Request $request): View
    {
        $companies = Company::query()->orderBy('name')->get(['id', 'name']);

        $query = Location::query()->with('company');

        if ($request->filled('company_id')) {
            $query->where('company_id', (int) $request->input('company_id'));
        }

        if ($request->filled('search')) {
            $search = $request->get('search');
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%")
                    ->orWhere('city', 'like', "%{$search}%");
            });
        }

        if ($request->filled('type') && in_array($request->get('type'), ['store', 'warehouse'], true)) {
            $query->where('type', $request->get('type'));
        }

        if ($request->filled('status')) {
            $status = $request->get('status');
            if ($status === 'active') {
                $query->where('is_active', true);
            } elseif ($status === 'inactive') {
                $query->where('is_active', false);
            }
        }

        $sortKey = $request->get('sort', 'type_priority');
        $sortMap = [
            'type_priority' => null,
            'name_asc' => ['name', 'asc'],
            'name_desc' => ['name', 'desc'],
            'updated_at_desc' => ['updated_at', 'desc'],
            'updated_at_asc' => ['updated_at', 'asc'],
            'priority_asc' => ['priority', 'asc'],
            'priority_desc' => ['priority', 'desc'],
        ];
        if (!array_key_exists($sortKey, $sortMap)) {
            $sortKey = 'type_priority';
        }

        if ($sortKey === 'type_priority') {
            $query->orderBy('type')->orderBy('priority');
        } else {
            [$sort, $order] = $sortMap[$sortKey];
            $query->orderBy($sort, $order)->orderBy('name');
        }

        $locations = $query->paginate(50)->withQueryString();

        $statsQuery = Location::query();
        if ($request->filled('company_id')) {
            $statsQuery->where('company_id', (int) $request->input('company_id'));
        }

        $stats = [
            'total' => (clone $statsQuery)->count(),
            'stores' => (clone $statsQuery)->where('type', 'store')->count(),
            'warehouses' => (clone $statsQuery)->where('type', 'warehouse')->count(),
            'active' => (clone $statsQuery)->where('is_active', true)->count(),
        ];

        return view('admin.locations.index', compact('locations', 'companies', 'stats', 'sortKey'));
    }

    public function create(): View
    {
        $company = Company::primary() ?? $this->locationService->ensureCompanyAndDefaults();

        return view('admin.locations.create', compact('company'));
    }

    public function store(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'company_id' => 'required|exists:companies,id',
            'code' => 'required|string|max:50|unique:locations,code',
            'name' => 'required|string|max:255',
            'type' => 'required|in:warehouse,store',
            'phone' => 'nullable|string|max:30',
            'email' => 'nullable|email',
            'address_line1' => 'nullable|string',
            'address_line2' => 'nullable|string',
            'city' => 'nullable|string|max:100',
            'state' => 'nullable|string|max:100',
            'pincode' => 'nullable|string|max:20',
            'latitude' => 'nullable|numeric',
            'longitude' => 'nullable|numeric',
            'priority' => 'nullable|integer|min:1',
            'is_active' => 'nullable|boolean',
            'fulfills_online' => 'nullable|boolean',
            'allows_pickup' => 'nullable|boolean',
            'is_default' => 'nullable|boolean',
        ]);

        $data['is_active'] = $request->boolean('is_active', true);
        $data['allows_pickup'] = $request->boolean('allows_pickup');
        $data['is_default'] = $request->boolean('is_default');
        $data['priority'] = $data['priority'] ?? 100;

        // Stores default to Fulfills Online so website stock includes them dynamically.
        // Warehouses never fulfill online (scopeFulfillsOnline is store-only).
        if (($data['type'] ?? null) === 'warehouse') {
            $data['fulfills_online'] = false;
        } else {
            $data['fulfills_online'] = $request->boolean('fulfills_online', true);
        }

        if ($data['is_default']) {
            Location::query()
                ->where('type', $data['type'])
                ->update(['is_default' => false]);
        }

        Location::create($data);

        return redirect()->route('admin.locations.index')->with('success', 'Location created.');
    }

    public function edit(Location $location): View
    {
        return view('admin.locations.edit', compact('location'));
    }

    public function update(Request $request, Location $location): RedirectResponse
    {
        $data = $request->validate([
            'code' => 'required|string|max:50|unique:locations,code,' . $location->id,
            'name' => 'required|string|max:255',
            'type' => 'required|in:warehouse,store',
            'phone' => 'nullable|string|max:30',
            'email' => 'nullable|email',
            'address_line1' => 'nullable|string',
            'address_line2' => 'nullable|string',
            'city' => 'nullable|string|max:100',
            'state' => 'nullable|string|max:100',
            'pincode' => 'nullable|string|max:20',
            'latitude' => 'nullable|numeric',
            'longitude' => 'nullable|numeric',
            'priority' => 'nullable|integer|min:1',
            'is_active' => 'nullable|boolean',
            'fulfills_online' => 'nullable|boolean',
            'allows_pickup' => 'nullable|boolean',
            'is_default' => 'nullable|boolean',
            'pickup_name' => 'nullable|string|max:255',
            'warehouse_pin' => 'nullable|string|max:20',
        ]);

        $data['is_active'] = $request->boolean('is_active', true);
        $data['fulfills_online'] = $request->boolean('fulfills_online');
        $data['allows_pickup'] = $request->boolean('allows_pickup');
        $data['is_default'] = $request->boolean('is_default');

        if (($data['type'] ?? null) === 'warehouse') {
            $data['fulfills_online'] = false;
        }

        if ($data['is_default']) {
            Location::query()
                ->where('type', $data['type'])
                ->where('id', '!=', $location->id)
                ->update(['is_default' => false]);
        }

        $settings = [
            'pickup_name' => $data['pickup_name'] ?? null,
            'warehouse_pin' => $data['warehouse_pin'] ?? null,
        ];
        unset($data['pickup_name'], $data['warehouse_pin']);

        $location->update($data);

        foreach ($settings as $key => $value) {
            if ($value !== null && $value !== '') {
                $location->setSetting($key, $value);
            } else {
                $location->settings()->where('key', $key)->delete();
            }
        }

        return redirect()->route('admin.locations.index')->with('success', 'Location updated.');
    }

    public function select(): View
    {
        $user = auth()->user();
        $locations = $this->locationService->accessibleLocations($user);
        $currentLocationId = $this->locationService->resolveLocationIdForUser($user);

        return view('admin.locations.select', compact('locations', 'currentLocationId'));
    }

    public function setCurrent(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'location_id' => 'required|exists:locations,id',
            'redirect_to' => 'nullable|string|max:2048',
        ]);

        $locationId = (int) $data['location_id'];

        if (!$this->locationService->userCanAccessLocation(auth()->user(), $locationId)) {
            abort(403, 'You cannot access this location.');
        }

        // Persist explicitly so the following redirect request reads the new value.
        $request->session()->put('current_location_id', $locationId);
        $request->session()->save();

        $location = Location::query()->find($locationId);
        $message = 'Location updated'.($location ? ': '.$location->name : '').'.';

        $target = $this->buildPostSwitchRedirect(
            $data['redirect_to'] ?? null,
            $location,
            $locationId,
            (string) ($request->headers->get('referer') ?? '')
        );

        return redirect()->to($target)->with('success', $message);
    }

    /**
     * Keep the user on the same admin page when possible, but force location_id
     * (and dashboard tab) to match the newly selected store/warehouse so the
     * next request cannot clobber session from a stale query string.
     */
    protected function buildPostSwitchRedirect(
        ?string $redirectTo,
        ?Location $location,
        int $locationId,
        string $referer
    ): string {
        $adminRoot = rtrim(url('/admin'), '/');
        $fallback = route('admin.dashboard', array_filter([
            'tab' => $location?->isWarehouse() ? 'warehouse' : 'store',
            'location_id' => $locationId,
        ]));

        $candidate = null;
        if (is_string($redirectTo) && $redirectTo !== '' && str_starts_with($redirectTo, $adminRoot)) {
            $candidate = $redirectTo;
        } elseif ($referer !== '' && str_starts_with($referer, $adminRoot)) {
            $candidate = $referer;
        }

        if (!$candidate || str_contains($candidate, '/admin/locations/select')) {
            return $fallback;
        }

        $parts = parse_url($candidate);
        $path = $parts['path'] ?? '/admin';
        parse_str($parts['query'] ?? '', $query);

        $query['location_id'] = (string) $locationId;

        $isDashboard = (bool) preg_match('#^/admin/?$#', $path)
            || (bool) preg_match('#^/admin/dashboard(?:/|$)#', $path);

        if ($isDashboard && $location) {
            $query['tab'] = $location->isWarehouse() ? 'warehouse' : 'store';
        }

        $url = url($path);
        $qs = http_build_query($query);

        return $qs !== '' ? ($url.'?'.$qs) : $url;
    }
}