<?php

namespace App\Http\Controllers\Backend;

use App\Http\Controllers\Controller;
use App\Models\OrderItem;
use App\Models\Shop;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class ShopController extends Controller
{
    public function index()
    {
        /** @var User|null $user */
        $user = Auth::user();

        if (! $user) {
            $shops = collect();
        } elseif ($user->hasRole('super-admin')) {
            $shops = Shop::with('creator')->latest()->get();
        } else {
            $shops = Shop::query()
                ->with('creator')
                ->where('created_by', $user->id)
                ->orWhereHas('users', function ($q) use ($user) {
                    $q->where('users.id', $user->id);
                })
                ->latest()
                ->get();
        }

        return view('backend.shops.index', compact('shops'));
    }

    public function create()
    {
        $this->authorize('create', Shop::class);

        return view('backend.shops.create');
    }

    public function store(Request $request)
    {
        $this->authorize('create', Shop::class);
        $request->validate([
            'name' => 'required|string|max:255|unique:shops,name',
            'logo' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:2048',
            'brand_color' => 'nullable|string|regex:/^#[a-fA-F0-9]{6}$/',
            'contact' => 'nullable|array',
            'contact.phone' => 'nullable|string|max:20',
            'contact.email' => 'nullable|email|max:255',
            'contact.address' => 'nullable|string|max:500',
            'users' => 'nullable|array',
            'users.*' => 'exists:users,id',
        ]);

        try {
            $data = $request->only(['name', 'brand_color', 'contact']);
            $data['created_by'] = Auth::id();

            if ($request->hasFile('logo')) {
                $data['logo'] = $request->file('logo')->store('shops', 'public');
            }

            $shop = Shop::create($data);

            $selectedUserIds = (array) $request->input('users', []);
            if ($shop->created_by) {
                $selectedUserIds[] = (int) $shop->created_by;
            }
            $selectedUserIds = array_values(array_unique(array_map('intval', $selectedUserIds)));

            if (! empty($selectedUserIds)) {
                $users = User::whereIn('id', $selectedUserIds)->get();

                foreach ($users as $user) {
                    if (! $user->hasRole('shop-staff')) {
                        $user->assignRole('shop-staff');
                    }
                }

                $shop->users()->syncWithoutDetaching($users->pluck('id')->toArray());
            }

            return redirect()->route('admin.shops.index')->with('success', 'Shop created successfully!');
        } catch (\Exception $e) {
            return redirect()->back()->withInput()->with('error', 'Failed to create shop. Please try again.');
        }
    }

    public function show(Shop $shop)
    {
        $this->authorize('manage', $shop);
        $shop->load('creator', 'users');
        return view('backend.shops.show', compact('shop'));
    }

    public function edit(Shop $shop)
    {
        $this->authorize('manage', $shop);
        $shop->load('users');
        return view('backend.shops.edit', compact('shop'));
    }

    public function update(Request $request, Shop $shop)
    {
        $this->authorize('manage', $shop);
        $request->validate([
            'name' => 'required|string|max:255|unique:shops,name,' . $shop->id,
            'logo' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:2048',
            'brand_color' => 'nullable|string|regex:/^#[a-fA-F0-9]{6}$/',
            'contact' => 'nullable|array',
            'contact.phone' => 'nullable|string|max:20',
            'contact.email' => 'nullable|email|max:255',
            'contact.address' => 'nullable|string|max:500',
            'users' => 'nullable|array',
            'users.*' => 'exists:users,id',
        ]);

        try {
            $data = $request->only(['name', 'brand_color', 'contact']);

            if ($request->hasFile('logo')) {
                if ($shop->logo) {
                    Storage::disk('public')->delete($shop->logo);
                }
                $data['logo'] = $request->file('logo')->store('shops', 'public');
            }

            $shop->update($data);

            if ($request->has('users_present')) {
                // Only sync when users[] is present. If JS fails to submit users[], keep existing links.
                $selectedUserIds = $request->input('users');
                if (is_array($selectedUserIds)) {
                    if ($shop->created_by) {
                        $selectedUserIds[] = (int) $shop->created_by;
                    }
                    $selectedUserIds = array_values(array_unique(array_map('intval', $selectedUserIds)));

                    $users = User::whereIn('id', $selectedUserIds)->get();

                    foreach ($users as $user) {
                        if (! $user->hasRole('shop-staff')) {
                            $user->assignRole('shop-staff');
                        }
                    }

                    $shop->users()->sync($users->pluck('id')->toArray());
                }
            }

            return redirect()->route('admin.shops.index')->with('success', 'Shop updated successfully!');
        } catch (\Exception $e) {
            return redirect()->back()->withInput()->with('error', 'Failed to update shop. Please try again.');
        }
    }

    public function destroy(Shop $shop)
    {
        $this->authorize('manage', $shop);

        if ($shop->logo) {
            Storage::disk('public')->delete($shop->logo);
        }
        $shop->delete();

        return redirect()->route('admin.shops.index')->with('success', 'Shop deleted successfully!');
    }

    public function searchUsers(Request $request)
    {
        $query = $request->get('q', '');
        $selected = $request->get('selected', '');
        $shopId = $request->integer('shop_id');

        // Convert comma-separated string to array and filter out empty values
        $selected = array_filter(explode(',', $selected));

        $users = User::where(function ($q) use ($query) {
            $q->where('name', 'LIKE', "%{$query}%")
                ->orWhere('email', 'LIKE', "%{$query}%");
        });

        // In edit mode: prevent assigning users already assigned to this shop (no duplicates in pivot)
        if ($shopId) {
            $users->whereDoesntHave('shops', function ($shopQuery) use ($shopId) {
                $shopQuery->where('shops.id', $shopId);
            });
        }

        $users = $users->whereNotIn('id', $selected)
            ->limit(20)
            ->get(['id', 'name', 'email']);

        return response()->json($users);
    }

    public function report(Shop $shop)
    {
        $this->authorize('manage', $shop);

        $shop->loadCount('products');

        $itemsQuery = OrderItem::query()
            ->where(function ($q) use ($shop) {
                $q->whereHas('product', function ($productQuery) use ($shop) {
                    $productQuery->where('shop_id', $shop->id);
                })->orWhere('shop_name', $shop->name);
            });

        $orderIds = (clone $itemsQuery)->pluck('order_id')->unique()->values();

        $summary = [
            'total_products' => (int) $shop->products_count,
            'in_stock_products' => (int) $shop->products()->where('stock', '>', 0)->count(),
            'orders_count' => $orderIds->count(),
            'items_sold' => (int) ((clone $itemsQuery)->sum('quantity') ?? 0),
            'gross_sales' => (float) ((clone $itemsQuery)->sum('line_total') ?? 0),
        ];

        $statusCounts = DB::table('orders')
            ->whereIn('id', $orderIds)
            ->select('status', DB::raw('count(*) as total'))
            ->groupBy('status')
            ->pluck('total', 'status');

        $recentOrders = DB::table('orders')
            ->whereIn('id', $orderIds)
            ->select('id', 'order_number', 'customer_name', 'phone', 'status', 'total_amount', 'created_at')
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        $topProducts = (clone $itemsQuery)
            ->select('product_name', DB::raw('SUM(quantity) as qty_sold'), DB::raw('SUM(line_total) as revenue'))
            ->groupBy('product_name')
            ->orderByDesc('qty_sold')
            ->limit(10)
            ->get();

        return view('backend.shops.report', compact('shop', 'summary', 'statusCounts', 'recentOrders', 'topProducts'));
    }

    public function createStaffUser(Request $request)
    {
        $request->validate([
            'name'     => 'required|string|max:255',
            'email'    => 'required|email|max:255|unique:users,email',
            'password' => 'required|string|min:8|confirmed',
            'shop_id'  => 'nullable|exists:shops,id',
        ]);

        $user = User::create([
            'name'     => $request->input('name'),
            'email'    => $request->input('email'),
            'password' => bcrypt($request->input('password')),
        ]);

        $user->assignRole('shop-staff');

        $shopId = $request->integer('shop_id') ?: null;
        if ($shopId) {
            $shop = Shop::find($shopId);
            if ($shop) {
                $shop->users()->syncWithoutDetaching([$user->id]);
            }
        }

        return redirect()
            ->route('admin.staff-assignment.index', ['user_id' => $user->id])
            ->with('success', 'User "' . $user->name . '" created and assigned as staff successfully!');
    }

    public function staffAssignment(Request $request)
    {
        $shops = Shop::query()->select('id', 'name')->orderBy('name')->get();
        $search = trim((string) $request->string('q', ''));

        $usersQuery = User::query()
            ->withCount('shops')
            ->when($search !== '', function ($query) use ($search) {
                $query->where(function ($innerQuery) use ($search) {
                    $innerQuery->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%");
                });
            })
            ->orderBy('name');

        $users = $usersQuery->paginate(15)->withQueryString();
        $selectedUserId = $request->integer('user_id') ?: null;
        $selectedUser   = $selectedUserId
            ? User::with('shops:id')->findOrFail($selectedUserId)
            : null;

        return view('backend.staff-assignment.index', compact('shops', 'users', 'search', 'selectedUser', 'selectedUserId'));
    }

    public function searchShopsForStaffAssignment(Request $request)
    {
        $query = trim((string) $request->string('q', ''));

        $shops = Shop::query()
            ->select('id', 'name')
            ->when($query !== '', function ($shopQuery) use ($query) {
                $shopQuery->where('name', 'like', "%{$query}%");
            })
            ->orderBy('name')
            ->limit(20)
            ->get();

        return response()->json($shops);
    }

    public function assignShopsToUser(Request $request)
    {
        $request->validate([
            'user_id'    => 'required|exists:users,id',
            'edit_name'  => 'required|string|max:255',
            'edit_email' => 'required|email|max:255',
            'edit_password' => 'nullable|string|min:8|confirmed',
            'shop_ids'   => 'nullable|array',
            'shop_ids.*' => 'exists:shops,id',
        ]);

        $user    = User::findOrFail($request->integer('user_id'));

        $request->validate([
            'edit_email' => 'required|email|max:255|unique:users,email,' . $user->id,
        ]);

        $updateData = [
            'name' => (string) $request->input('edit_name'),
            'email' => (string) $request->input('edit_email'),
        ];

        if ($request->filled('edit_password')) {
            $updateData['password'] = (string) $request->input('edit_password');
        }

        $user->update($updateData);

        if ($request->has('shop_ids')) {
            $shopIds = array_values(array_unique(array_map('intval', (array) $request->input('shop_ids', []))));

            if (! empty($shopIds) && ! $user->hasRole('shop-staff')) {
                $user->assignRole('shop-staff');
            }

            // Preserve shops where the user is the creator (don't remove those via pivot sync)
            $createdShopIds = Shop::where('created_by', $user->id)->pluck('id')->toArray();
            $mergedIds      = array_values(array_unique(array_merge($shopIds, $createdShopIds)));

            $user->shops()->sync($mergedIds);
        }

        return redirect()
            ->route('admin.staff-assignment.index', ['user_id' => $user->id])
            ->with('success', 'User updated successfully.');
    }

    public function storeStaffAssignment(Request $request)
    {
        // Legacy endpoint — redirect to new user-centric assignment
        return redirect()->route('admin.staff-assignment.index');
    }

    public function deleteStaffUser(User $user)
    {
        if ((int) Auth::id() === (int) $user->id) {
            return redirect()->route('admin.staff-assignment.index')->with('error', 'You cannot delete your own account.');
        }

        if ($user->hasRole('super-admin')) {
            return redirect()->route('admin.staff-assignment.index')->with('error', 'Super Admin user cannot be deleted from this page.');
        }

        $user->shops()->detach();
        $user->delete();

        return redirect()->route('admin.staff-assignment.index')->with('success', 'User deleted successfully.');
    }

    public function getUserShopAssignments(User $user)
    {
        $shops = Shop::query()->select('id', 'name')->orderBy('name')->get();
        $assignedIds = $user->shops()->pluck('shops.id')->map(fn ($id) => (int) $id)->values();

        return response()->json([
            'user' => [
                'id' => (int) $user->id,
                'name' => (string) $user->name,
            ],
            'assigned_shop_ids' => $assignedIds,
            'shops' => $shops,
        ]);
    }

    public function updateUserShopAssignments(Request $request, User $user)
    {
        $request->validate([
            'shop_ids' => 'nullable|array',
            'shop_ids.*' => 'exists:shops,id',
        ]);

        $shopIds = array_values(array_unique(array_map('intval', (array) $request->input('shop_ids', []))));

        if (! empty($shopIds) && ! $user->hasRole('shop-staff')) {
            $user->assignRole('shop-staff');
        }

        $createdShopIds = Shop::where('created_by', $user->id)->pluck('id')->toArray();
        $mergedIds = array_values(array_unique(array_merge($shopIds, $createdShopIds)));

        $user->shops()->sync($mergedIds);

        return response()->json([
            'message' => 'Shop assignments updated successfully.',
            'count' => count($mergedIds),
        ]);
    }
}
