<?php

declare(strict_types=1);

namespace App\Http\Controllers\Market;

use App\Enums\UserActions;
use App\Enums\UserTypes;
use App\Http\Controllers\Helpers\Permissions\ProductPermissions;
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
use App\Http\Controllers\Helpers\PhotoURL;
use App\Http\Controllers\Helpers\ResponseHelper;
use App\Models\Market\Product;
use App\Models\Market\ProductTransaction;
use App\Models\Market\Store;
use App\Models\User;
use Exception;
use Hyperf\Database\Model\ModelNotFoundException;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Auth;
use Hypervel\Support\Facades\Config;
use Hypervel\Support\Facades\DB;
use Hypervel\Support\Facades\Response;

class ProductController
{


    public function createNew_Admin(Request $request)
    {
        /** @var User $user */
        $user = Auth::user();
        //TODO Fix this permissions check to be unified with PRoductpermissions

        // $IsAdmin = in_array($user?->acct_type, [
        //     UserTypes::ULTIMATE,
        //     UserTypes::OPERATOR,
        //     UserTypes::SUPER_OPERATOR,
        // ], true);

        // if (!$user || !$IsAdmin) {
        //     return response()->json(['success' => false, 'message' => 'Unauthorized '], 403);
        // }

        $canCreateGlobal = ProductPermissions::isActionAllowed(UserActions::CreateProductGlobal);
        $canCreateForOwnStore = ProductPermissions::isActionAllowed(UserActions::CreateProductForOwnStore);

        if (!$canCreateGlobal && !$canCreateForOwnStore) {
            return ResponseHelper::returnUnauthorized();
        }

        // Validate request input
        $validated = $request->validate([
            'NewProductName' => 'required|string|max:255',
            'NewProductAvailable' => 'required|numeric',
            'NewProductBarcode' => 'nullable|string|max:255',
            'NewProductCategory' => 'nullable|string|max:255',
            'NewProductSubCategory' => 'nullable|string|max:255',
            'NewProductDescription' => 'required|string',
            'NewProductPrice' => 'required|numeric|min:0',
            'NewProductUnitName' => 'required|string|max:100',
            'files' => 'nullable|array',
            'photourl' => 'nullable|array',
            'TargetStore' => 'nullable|string',
        ]);

        $targetStoreHash = $validated['TargetStore'] ?? null;
        $targetStore = null;

        if (!$canCreateGlobal && !$targetStoreHash) {
            return ResponseHelper::returnUnauthorized('A target store is required to create a product.');
        }

        if ($targetStoreHash) {
            $targetStore = Store::where('hashkey', $targetStoreHash)->first();
            if (!$targetStore) {
                return response()->json(['success' => false, 'message' => 'Target store not found'], 404);
            }

            // Permission check for target store
            /** @var User $user */
            $user = Auth::user();
            $acctType = $user->acct_type instanceof UserTypes ? $user->acct_type : UserTypes::tryFrom($user->acct_type);
            $isBig3 = in_array($acctType, [UserTypes::ULTIMATE, UserTypes::SUPER_OPERATOR, UserTypes::OPERATOR]);
            
            $isAllowedAccess = false;
            if ($isBig3) {
                $isAllowedAccess = true;
            } else {
                // Owner, Primary Manager, or New Managers list
                if ($targetStore->owner_id === $user->id || $targetStore->manager_id === $user->id) {
                    $isAllowedAccess = true;
                } elseif ($targetStore->managers()->where('user_id', $user->id)->exists()) {
                    $isAllowedAccess = true;
                } else {
                    // Ancestor check
                    if (UserPermissions::isDescendantOfCurrentUser($targetStore->owner_id)) {
                        $isAllowedAccess = true;
                    } else {
                        $managerIds = $targetStore->managerUsers()->pluck('users.id')->toArray();
                        foreach ($managerIds as $managerId) {
                            if (UserPermissions::isDescendantOfCurrentUser($managerId)) {
                                $isAllowedAccess = true;
                                break;
                            }
                        }
                    }
                }
            }

            if (!$isAllowedAccess) {
                return ResponseHelper::returnUnauthorized();
            }
        }

        // Create new product
        $product = Product::create([
            'name' => $validated['NewProductName'],
            'description' => $validated['NewProductDescription'],
            'price' => $validated['NewProductPrice'],
            'unitname' => $validated['NewProductUnitName'],
            'available' => $validated['NewProductAvailable'],
            'barcode' => $validated['NewProductBarcode'] ?? null,
            'category' => $validated['NewProductCategory'] ?? null,
            'subcategory' => $validated['NewProductSubCategory'] ?? null,
            'photourl' => $validated['photourl'] ?? $validated['files'] ?? null,
            'created_by' => $user->id,
        ]);
 
        if ($product) {
            if ($targetStore) {
                /** @var Store $targetStore */
                /** @var Product $product */
                StoreController::attachProducttoStore($targetStore, $product, (int) $product->available, (int) $product->price);
            }

            return response()->json([
                'success' => true,
                'data' => [
                    'hashkey' => $product->hashkey,
                ],
            ]);
        }

        return response()->json(['success' => false, 'message' => 'Failed to create product'], 500);
    }


    private static function searchProductTypes($array, $searchTerm)
    {
        $results = [];
        foreach ($array as $key => $value) {
            if (stripos($key, $searchTerm) !== false) {
                $results[$key] = $value;
            }
            if (is_array($value)) {
                $recursiveResults = self::searchProductTypes($value, $searchTerm);

                foreach ($recursiveResults as $rKey => $rValue) {
                    if (array_key_exists($rKey, $results)) {
                        if (is_array($results[$rKey]) && is_array($rValue)) {
                            $results[$rKey] = array_merge_recursive($results[$rKey], $rValue);
                        } else {
                            $results[$rKey] = array($results[$rKey], $rValue);
                        }
                    } else {
                        $results[$rKey] = $rValue;
                    }
                }
            }
        }
        return $results;
    }

    public function getCategories(Request|false $request = false)
    {
        $nonRequest = $request == false;



        if (!$nonRequest) {
            $category = $request->input('category');
        } else {
            $category = false;
        }

        $categories = array_keys(Config::get('market.productsCategorySubcategory'));

        if (!$nonRequest) {
            return response()->json([
                'success' => true,
                'categories' => $categories,
            ]);
        }

        return $categories;
    }

    public function getSubcategories(Request|false $request = false, string|false $category = false)
    {

        $request = $request ?: request();
        $category = $request ? $request->input('category') : $category;

        $categoryList = Config::get('market.productsCategorySubcategory', []);

        if (!$category || !array_key_exists($category, $categoryList)) {
            if ($request) {
                return response()->json([], 400);
            }
            return [];
        }

        $subcategories = $categoryList[$category] ?? [];

        if ($request) {
            return response()->json($subcategories);
        }

        return $subcategories;
    }


    public static function viewProductDetails(string|false $target = false, $withStores = false)
    {
        $hashfromRequest = request()->input('target');
        $datafromRequest = request()->input('data');
        $targetStoreHash = null;
        $hashkey = $hashfromRequest ?? $target;
        $storeProductAvailable = null;
        $storeProductPrice = null;
        $storeProductIsActive = null;
        $storeProductRemarks = null;
        $storeProductDescription = null;
        $storeProductSold = null;
        $storeProductReviews = null;
        $isFromStore = false;
        $storeProductQrCode = null;


     



        if ($datafromRequest && is_array($datafromRequest) && isset($datafromRequest['store_hash'])) {
            $targetStoreHash = $datafromRequest['store_hash'];
            try {
                $targetStore = Store::where('hashkey', $targetStoreHash)->firstOrFail();
            } catch (\Throwable $th) {
                return ResponseHelper::returnIncorrectDetails();
            }
        } else {
            $targetStore = null;
        }




        if (!$hashkey || is_numeric($hashkey)) {
            return ResponseHelper::returnFalseOrNull($hashfromRequest);
        }



        $product = Product::where('hashkey', $hashkey)
            ->first();

        if (!$product) {
            return ResponseHelper::returnFalseOrNull($hashfromRequest);
        }




        if ($targetStore) {
            $storeProduct = $targetStore->products()
                ->where('prd_items.id', $product->id)
                ->first();

            if (!$storeProduct) {
                return ResponseHelper::returnFalseOrNull($hashfromRequest);
            }

            $isFromStore = true;

            $storeProductAvailable = $storeProduct->pivot->available;
            $storeProductPrice = $storeProduct->pivot->price;
            $storeProductIsActive = $storeProduct->pivot->is_active;
            $storeProductRemarks = $storeProduct->pivot->remarks;
            $storeProductDescription = $storeProduct->pivot->description;
            $storeProductSold = $storeProduct->pivot->sold;
            $storeSoldToday = ProductTransaction::where('product_id', $product->id)
                ->where('store_id', $targetStore->id)
                ->whereDate('created_at', today())
                ->sum('quantity');
            $storeProductReviews = $storeProduct->pivot->reviews;

            // Store specific QR code: hashkey of product + store
            $storeProductQrCode = md5($product->hashkey . $targetStore->hashkey);
        }

        $soldToday = ProductTransaction::where('product_id', $product->id)
            ->whereDate('created_at', today())
            ->sum('quantity');


        // $productActive = $product->status === 'active';
        // $productStockAvailable = $product->available > 0;
        // $storeActive = $store && $store->status === 'active';

        // if (!$store || !$productActive || !$productStockAvailable || !$storeActive) {
        //     if ($hashfromRequest) {
        //         return response()->json(['success' => false]);
        //     } else {
        //         return null;
        //     }
        // }



        $data = [
            'hashkey' => $product->hashkey,
            'name' => $product->name,
            'store_description' => $storeProductDescription,
            'description' => $product->description,
            'category' => $product->category,
            'subcategory' => $product->subcategory,
            'unitname' => $product->unitname,
            'is_from_store' => $isFromStore,
            'price' => $product->price,
            'store_price' => $storeProductPrice,
            'store_available' => $storeProductAvailable,
            'available' => $product->available,

            'store_sold' => $storeProductSold,
            'sold' => $product->sold,
            'sold_today' => (int) $soldToday,
            'store_sold_today' => isset($storeSoldToday) ? (int) $storeSoldToday : null,

            'store_reviews' => $storeProductReviews,
            'reviews' => $product->reviews,

            'store_remarks' => $storeProductRemarks,
            'remarks' => $product->remarks,
            'photourl' => $product->photourl,
            'barcode' => $product->barcode,
            'pos_qrcode' => $storeProductQrCode ?? $product->barcode ?? $product->hashkey,
            'is_active' => $storeProductIsActive ?? $product->is_active,
        ];


        if ($withStores) {
            $data['store_options'] = Store::select(['hashkey', 'name'])
                ->get()
                ->map(function ($store) {
                    return [$store->hashkey, $store->name];
                });
        }




        if ($data['photourl']) {
            $data['photourlDropzone'] = PhotoURL::photoURLArraytoDropzoneData($data['photourl']);
        }

        if ($hashfromRequest) {
            return ResponseHelper::returnSuccessResponse($data, $data['hashkey']);
        } else {
            return $data;
        }
    }
    public static function viewProductDetailsByStoreEdit(string|false $target = false, $withStores = false)
    {
        // This method is intended to be called when we specifically want to view a product
        // in the context of a store (e.g., for store-specific editing).
        // It ensures store_hash is present or identifies it from context.
        
        $req = request();
        $target = $target ?: $req->input('target');
        $storeHash = $req->input('store_hash') ?? ($req->input('data')['store_hash'] ?? null);

        if (!$storeHash) {
            // Fallback: If no store hash is provided, maybe we shouldn't allow store-specific view?
            // But for now, let's let viewProductDetails handle the fallback.
        }

        return self::viewProductDetails($target, $withStores);
    }



    public static function editProductAdmin(Request|false $request = false, string|false $target = false)
    {
        /** @var User $user */
        $user = Auth::user();
        $acctType = $user->acct_type instanceof UserTypes ? $user->acct_type : UserTypes::tryFrom($user->acct_type);
        $isBig3 = in_array($acctType, [UserTypes::ULTIMATE, UserTypes::SUPER_OPERATOR, UserTypes::OPERATOR]);

        $req = $request ?: request();
        $hash = $target ?: ($req?->input('target') ?? null);
        $data = $req?->input('data') ?? [];
        $storeHash = $data['store_hash'] ?? null;

        // Global edit requires ModifyAllProducts. Per-store edits are gated
        // below by per-store ownership instead.
        $canModifyGlobal = ProductPermissions::isActionAllowed(UserActions::ModifyAllProducts);
        $canModifyOwnStoreProduct = ProductPermissions::isActionAllowed(UserActions::ModifyOwnProduct)
            || ProductPermissions::isActionAllowed(UserActions::AddProducttoOwnStore);

        if (!$canModifyGlobal && !($storeHash && $canModifyOwnStoreProduct)) {
            return $target ? false : ResponseHelper::returnUnauthorized();
        }

        if (!$hash) {
            return $target ? false : response()->json(['success' => false, 'message' => 'No target specified'], 400);
        }

        $product = Product::where('hashkey', $hash)->first();

        if (!$product) {
            return $target ? false : response()->json(['success' => false, 'message' => 'Product not found'], 404);
        }

        $isStoreUpdate = (bool)$storeHash;
        
        $validated = $req->validate([
            'EditProductName' => $isStoreUpdate ? 'nullable|string|max:255' : 'required|string|max:255',
            'EditProductAvailable' => 'nullable|numeric',
            'EditProductBarcode' => 'nullable|string|max:255',
            'EditProductCategory' => 'nullable|string|max:255',
            'EditProductSubCategory' => 'nullable|string|max:255',
            'EditProductDescription' => 'required|string',
            'EditProductPrice' => 'required|numeric|min:0',
            'EditProductUnitName' => $isStoreUpdate ? 'nullable|string|max:100' : 'required|string|max:100',
            'files' => 'nullable|array',
            'photourl' => 'nullable|array',
            'status' => 'nullable|boolean',
        ]);

        if ($storeHash) {
            $store = Store::where('hashkey', $storeHash)->first();
            if ($store) {
                $isAllowedAccess = false;
                if ($isBig3) {
                    $isAllowedAccess = true;
                } else {
                    if ($store->owner_id === $user->id || $store->manager_id === $user->id || $store->managers()->where('user_id', $user->id)->exists()) {
                        $isAllowedAccess = true;
                    } else {
                        if (UserPermissions::isDescendantOfCurrentUser($store->owner_id)) {
                             $isAllowedAccess = true;
                        } else {
                            $managerIds = $store->managerUsers()->pluck('users.id')->toArray();
                            foreach ($managerIds as $managerId) {
                                if (UserPermissions::isDescendantOfCurrentUser($managerId)) {
                                    $isAllowedAccess = true;
                                    break;
                                }
                            }
                        }
                    }
                }

                if ($isAllowedAccess) {
                    $product->stores()->syncWithoutDetaching([
                        $store->id => [
                            'available' => $validated['EditProductAvailable'] ?? 0,
                            'price' => $validated['EditProductPrice'] ?? 0,
                            'is_active' => $validated['status'] ?? true,
                            'description' => $validated['EditProductDescription'],
                            'remarks' => $validated['EditProductDescription'], // Keep for compatibility
                        ]
                    ]);

                    return $target ? true : response()->json([
                        'success' => true,
                        'message' => 'Store-specific product data updated successfully',
                        'hashkey' => $product->hashkey,
                    ]);
                }
            }
        }

        // PERMISSION CHECK: Restrict global product editing exclusively to the "Big 3" roles.
        if (!$isBig3) {
            return $target ? false : ResponseHelper::returnError('Global product editing is restricted to administrators.', 403);
        }

        $product->update([
            'name' => $validated['EditProductName'],
            'description' => $validated['EditProductDescription'],
            'price' => $validated['EditProductPrice'],
            'unitname' => $validated['EditProductUnitName'],
            'available' => $validated['EditProductAvailable'] ?? $product->available,
            'barcode' => $validated['EditProductBarcode'] ?? null,
            'category' => $validated['EditProductCategory'] ?? null,
            'subcategory' => $validated['EditProductSubCategory'] ?? null,
            'photourl' => $validated['photourl'] ?? $validated['files'] ?? $product->photourl,
            'is_active' => $validated['status'] ?? $product->is_active,
        ]);

        return $target ? true : response()->json([
            'success' => true,
            'message' => $product->wasChanged() ? 'Product updated successfully' : 'No changes were needed',
            'hashkey' => $product->hashkey,
        ]);
    }


    public static function editProductAdminByStore(Request|false $request = false, string|false $target = false)
    {
        $req = $request ?: request();

        $hash = $target ?: ($req?->input('target') ?? null);

        if (!$hash) {
            return $target ? false : response()->json(['success' => false, 'message' => 'No target specified'], 400);
        }

        $product = Product::where('hashkey', $hash)->first();

        if (!$product) {
            return $target ? false : response()->json(['success' => false, 'message' => 'Product not found'], 404);
        }

        // return response()->json(['success' => false, 'message' => 'Product not found'], 404);



        $validated = $req->validate([
            'EditProductName' => 'required|string|max:255',
            // 'EditProductAvailable' => 'required|numeric',
            'EditProductBarcode' => 'nullable|string|max:255',
            'EditProductCategory' => 'nullable|string|max:255',
            'EditProductSubCategory' => 'nullable|string|max:255',
            'EditProductDescription' => 'required|string',
            'EditProductPrice' => 'required|numeric|min:0',
            'EditProductUnitName' => 'required|string|max:100',
            'files' => 'nullable|array',
            // 'status' => 'nullable|boolean',
        ]);

        //TODO Check first if store_id is owned by current user or is descendant
        //TODO Then update the pivot table instead of the main product table


        $product->update([
            // 'name' => $validated['EditProductName'],
            'description' => $validated['EditProductDescription'],
            'price' => $validated['EditProductPrice'],

            // 'available' => $validated['EditProductAvailable'],
            // 'barcode' => $validated['EditProductBarcode'] ?? null,
            // 'is_active' => $validated['status'] ?? $product->is_active, // uncomment if you include this field
        ]);

        if ($product->wasChanged()) {
            return $target ? true : response()->json([
                'success' => true,
                'message' => 'Product updated successfully',
                'hashkey' => $product->hashkey,
            ]);
        }

        return $target ? false : response()->json([
            'success' => false,
            'message' => 'No changes were made',
        ], 500);
    }

    public function listProductsData(Request $request)
    {
        // $wholesaleOnly = $request->boolean('wholesale_only', false);

        // Fetch active and available products

        $user = Auth::user();
        $UltOpsSupOps = $user && in_array($user->acct_type, [
            UserTypes::ULTIMATE,
            UserTypes::OPERATOR,
            UserTypes::SUPER_OPERATOR,
        ], true);

        $storeHash = $request->input('store_hash');
        $accessKey = $request->input('access_key');
        $targetStore = null;

        $sessionHash = $request->input('session_hash');
        
        if ($accessKey) {
            $keyObj = \App\Models\Market\PosAccessKey::where('access_key', $accessKey)->first();
            if ($keyObj) {
                $targetStore = $keyObj->store;
            }
        }

        if (!$targetStore && $sessionHash) {
            $sessionObj = \App\Models\Market\PosSession::where('hashkey', $sessionHash)->first();
            if ($sessionObj) {
                $targetStore = $sessionObj->store;
            }
        }

        if (!$targetStore && $storeHash) {
            $targetStore = Store::where('hashkey', $storeHash)->first();
        }

        if ($targetStore) {
            $products = $targetStore->products()
                ->where('prd_str.is_active', true)
                ->get();
        } elseif ($UltOpsSupOps) {
            $products = Product::select(['description', 'name', 'price', 'unitname', 'photourl', 'hashkey', 'barcode'])->get();
        } else {
            $products = Product::where('is_active', true)
                ->get();
        }

        $products = $products->map(function ($product) use ($targetStore) {
            $photo = $product->photourl;
            
            $price = $product->price;
            $qrcode = $product->barcode ?? $product->hashkey;
            $available = $product->available;

            if ($targetStore && isset($product->pivot)) {
                $price = $product->pivot->price ?? $product->price;
                $qrcode = md5($product->hashkey . $targetStore->hashkey);
                $available = $product->pivot->available ?? $product->available;
            }

            return [
                'description' => $product->description,
                'name' => $product->name,
                'price' => $price,
                'unit' => $product->unitname,
                'photo' => $photo,
                'hashkey' => $product->hashkey,
                'barcode' => $product->barcode,
                'qrcode' => $qrcode,
                'category' => $product->category,
                'available' => $available,
            ];
        });

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

    public function viewProductwithAddStoreData()
    {
        $hashfromRequest = request()->input('target');


        if (!$hashfromRequest || is_numeric($hashfromRequest)) {
            return ResponseHelper::returnFalseOrNull($hashfromRequest);
        }
        return self::viewProductDetails($hashfromRequest, true);
    }

    public function AddProducttoStore()
    {
        /** @var User $user */
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $storeHash = request()->input('TargetStore');
        $productHash = request()->input('target');

        if (!$storeHash || !$productHash) {
            return ResponseHelper::returnIncorrectDetails();
        }

        // Check both global and own-store permissions
        $allowedAny = ProductPermissions::isActionAllowed(userActions::AddProducttoAnyStore);
        if (!$allowedAny) {
            $allowedOwn = ProductPermissions::isActionAllowed(userActions::AddProducttoOwnStore, $productHash, $storeHash);
            if (!$allowedOwn) {
                return ResponseHelper::returnUnauthorized();
            }
        }

        try {
            /** @var Store $store */
            $storeObj = Store::where('hashkey', $storeHash)->firstOrFail();
            /** @var Product $product */
            $productObj = Product::where('hashkey', $productHash)->firstOrFail();
        } catch (ModelNotFoundException $e) {
            return ResponseHelper::returnFalseOrNull('Store or Product not found');
        }

        try {
            StoreController::attachProducttoStore($storeObj, $productObj);
            return ResponseHelper::returnSuccessResponse([], $productObj);
        } catch (\Throwable $th) {
            if (str_contains($th->getMessage(), 'Duplicate entry')) {
                return ResponseHelper::returnError('Already Added to Store');
            }
            return ResponseHelper::returnError('Failed to add product to store: ' . $th->getMessage());
        }
    }

    public function RemoveProductFromStore()
    {
        /** @var User $user */
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $storeHash = request()->input('TargetStore');
        $productHash = request()->input('target');

        if (!$storeHash || !$productHash) {
            return ResponseHelper::returnIncorrectDetails();
        }

        try {
            $store = Store::where('hashkey', $storeHash)->firstOrFail();
            $product = Product::where('hashkey', $productHash)->firstOrFail();
        } catch (ModelNotFoundException $e) {
            return ResponseHelper::returnFalseOrNull('Store or Product not found');
        }

        $acctType = $user->acct_type instanceof UserTypes ? $user->acct_type : UserTypes::tryFrom($user->acct_type);
        $isBig3 = in_array($acctType, [UserTypes::ULTIMATE, UserTypes::SUPER_OPERATOR, UserTypes::OPERATOR]);

        $isAllowedAccess = false;
        if ($isBig3) {
            $isAllowedAccess = true;
        } elseif ($store->owner_id === $user->id || $store->manager_id === $user->id || $store->managers()->where('user_id', $user->id)->exists()) {
            $isAllowedAccess = true;
        } elseif (UserPermissions::isDescendantOfCurrentUser($store->owner_id)) {
            $isAllowedAccess = true;
        } else {
            foreach ($store->managerUsers()->pluck('users.id')->toArray() as $managerId) {
                if (UserPermissions::isDescendantOfCurrentUser($managerId)) {
                    $isAllowedAccess = true;
                    break;
                }
            }
        }

        if (!$isAllowedAccess) {
            return ResponseHelper::returnUnauthorized();
        }

        try {
            if ($store->products()->where('prd_items.id', $product->id)->exists()) {
                $store->products()->detach($product->id);
                return ResponseHelper::returnSuccessResponse([], $product);
            } else {
                return ResponseHelper::returnError('Product not attached to this store');
            }
        } catch (\Throwable $th) {
            return ResponseHelper::returnFalseOrNull($th->getMessage());
        }
    }

    /**
     * Return the set of store hashes (from the user's selectable stores) where this product is currently assigned.
     */
    public function getAssignedStoresForProduct()
    {
        /** @var User $user */
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $productHash = request()->input('target');
        if (!$productHash) {
            return ResponseHelper::returnIncorrectDetails();
        }

        try {
            $product = Product::where('hashkey', $productHash)->firstOrFail();
        } catch (ModelNotFoundException $e) {
            return ResponseHelper::returnFalseOrNull('Product not found');
        }

        $storeHashes = $product->stores()->pluck('str.hashkey')->toArray();

        return response()->json([
            'success' => true,
            'data' => $storeHashes,
        ]);
    }


    /**
     * Assign a product to a store with ownership-aware permissions.
     * - Ultimate/SuperOperator/Operator: can assign to any store
     * - Store Owner: can assign to stores they own
     * - Store Manager: can assign to stores they manage
     */
    public function AssignProductToOwnStore()
    {
        /** @var User $user */
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }
        $acctType = $user->acct_type instanceof UserTypes ? $user->acct_type : UserTypes::tryFrom($user->acct_type);
        $isBig3 = in_array($acctType, [UserTypes::ULTIMATE, UserTypes::SUPER_OPERATOR, UserTypes::OPERATOR]);
        $storeHash = request()->input('TargetStore');
        $productHash = request()->input('target');
        
        $price = request()->input('price');
        $available = request()->input('available');
        $description = request()->input('description');

        if (!$storeHash || !$productHash) {
            return ResponseHelper::returnIncorrectDetails();
        }

        try {
            $store = Store::where('hashkey', $storeHash)->firstOrFail();
            $product = Product::where('hashkey', $productHash)->firstOrFail();
        } catch (ModelNotFoundException $e) {
            return ResponseHelper::returnFalseOrNull('Store or Product not found');
        }

        // Big 3 always allowed.
        $isAllowedAccess = false;
        if ($isBig3) {
            $isAllowedAccess = true;
        } else {
            if ($store->owner_id === $user->id || $store->manager_id === $user->id || $store->managers()->where('user_id', $user->id)->exists()) {
                $isAllowedAccess = true;
            } else {
                if (UserPermissions::isDescendantOfCurrentUser($store->owner_id)) {
                    $isAllowedAccess = true;
                } else {
                    $managerIds = $store->managerUsers()->pluck('users.id')->toArray();
                    foreach ($managerIds as $managerId) {
                        if (UserPermissions::isDescendantOfCurrentUser($managerId)) {
                            $isAllowedAccess = true;
                            break;
                        }
                    }
                }
            }
        }

        if (!$isAllowedAccess) {
            return ResponseHelper::returnUnauthorized();
        }

        try {
            /** @var Store $store */
            /** @var Product $product */
            $pivotData = [
                'available' => (int) ($available ?? 0),
                'price' => (float) ($price ?? 0),
                'is_active' => true,
            ];
            if ($description !== null && $description !== '') {
                $pivotData['description'] = $description;
            }

            $existing = $store->products()->where('prd_items.id', $product->id)->exists();
            if ($existing) {
                $store->products()->updateExistingPivot($product->id, $pivotData);
            } else {
                $store->products()->attach($product->id, $pivotData);
            }

            return ResponseHelper::returnSuccessResponse(
                ['store_hash' => $storeHash, 'product_hash' => $productHash],
                $product->hashkey,
                'Product assigned to store successfully'
            );
        } catch (\Throwable $th) {
            return ResponseHelper::returnError('Failed to assign product to store: ' . $th->getMessage());
        }
    }


    public function listProducts_Admin(Request $request)
    {
        /** @var User $user */
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $acctType = $user->acct_type instanceof UserTypes ? $user->acct_type : UserTypes::tryFrom($user->acct_type);
        $isBig3 = in_array($acctType, [UserTypes::ULTIMATE, UserTypes::SUPER_OPERATOR, UserTypes::OPERATOR]);

        if ($isBig3) {
            $products = Product::select(['id', 'hashkey', 'name', 'price', 'unitname', 'available', 'is_active', 'photourl', 'category', 'subcategory', 'created_by'])
                ->orderBy('id', 'desc')
                ->get();
        } else {
            // Non-big 3 users see their own and their descendants' products,
            // plus any products assigned to stores they own or manage.
            /** @var User $user */
            $allowedIds = array_merge([$user->id], $user->getAllDescendants()->pluck('id')->toArray());

            $myStoreIds = Store::where(function ($q) use ($allowedIds) {
                $q->whereIn('owner_id', $allowedIds)
                  ->orWhereIn('manager_id', $allowedIds)
                  ->orWhereHas('managers', function ($mq) use ($allowedIds) {
                      $mq->whereIn('user_id', $allowedIds);
                  });
            })->pluck('id')->toArray();

            $assignedProductIds = DB::table('prd_str')
                ->whereIn('store_id', $myStoreIds)
                ->pluck('product_id')
                ->toArray();

            $products = Product::where(function ($q) use ($allowedIds, $assignedProductIds) {
                    $q->whereIn('created_by', $allowedIds)
                      ->orWhereIn('id', $assignedProductIds);
                })
                ->select(['id', 'hashkey', 'name', 'price', 'unitname', 'available', 'is_active', 'photourl', 'category', 'subcategory', 'created_by'])
                ->orderBy('id', 'desc')
                ->get();
        }

        return response()->json([
            'success' => true,
            'products' => $products
        ]);
    }

    public function listGlobalProductsForPicker(Request $request)
    {
        /** @var User $user */
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $products = Product::where('is_active', true)
            ->select(['id', 'hashkey', 'name', 'price', 'unitname', 'available', 'is_active', 'photourl', 'category', 'subcategory', 'description'])
            ->orderBy('name', 'asc')
            ->get();

        return response()->json([
            'success' => true,
            'products' => $products,
        ]);
    }

    public function deleteProduct_Admin(Request $request)
    {
        $user = Auth::user();
        $isUltimate = $user && $user->acct_type === UserTypes::ULTIMATE;

        $canDeleteAny = ProductPermissions::isActionAllowed(UserActions::DeleteAllProducts);
        $canDeleteOwn = ProductPermissions::isActionAllowed(UserActions::DeleteOwnProduct);
        if (!$canDeleteAny && !$canDeleteOwn) {
            return ResponseHelper::returnUnauthorized();
        }

        $hash = $request->input('target');
        if (!$hash) {
            return ResponseHelper::returnIncorrectDetails();
        }

        try {
            $product = Product::where('hashkey', $hash)->firstOrFail();

            // PERMISSION CHECK: If not ultimate, must be the creator (or a
            // descendant ancestor of the creator).
            if (!$isUltimate && (int) $product->created_by !== (int) $user->id) {
                if (!UserPermissions::isDescendantOfCurrentUser((int) $product->created_by)) {
                    return ResponseHelper::returnUnauthorized('You can only delete products you created.');
                }
            }

            $product->delete();
            return ResponseHelper::returnSuccessResponse([], $hash, 'Product deleted successfully');
        } catch (Exception $e) {
            return ResponseHelper::returnError('Failed to delete product: ' . $e->getMessage());
        }
    }

    public function toggleProductStatus_Admin(Request $request)
    {
        $user = Auth::user();
        $isUltimate = $user && $user->acct_type === UserTypes::ULTIMATE;

        $hash = $request->input('target');
        $data = $request->input('data') ?? [];
        $storeHash = $data['store_hash'] ?? null;

        if (!$hash) {
            return ResponseHelper::returnIncorrectDetails();
        }

        // Toggling a per-store override is gated by store ownership below.
        // Toggling the global product flag requires ModifyAllProducts.
        $canModifyGlobal = ProductPermissions::isActionAllowed(UserActions::ModifyAllProducts);
        $canModifyOwnStoreProduct = ProductPermissions::isActionAllowed(UserActions::ModifyOwnProduct)
            || ProductPermissions::isActionAllowed(UserActions::AddProducttoOwnStore);

        if (!$canModifyGlobal && !($storeHash && $canModifyOwnStoreProduct)) {
            return ResponseHelper::returnUnauthorized();
        }

        try {
            $product = Product::where('hashkey', $hash)->firstOrFail();

            if ($storeHash) {
                $store = Store::where('hashkey', $storeHash)->first();
                if ($store) {
                    $isOwnStore = (int) $store->owner_id === (int) $user->id || (int) $store->manager_id === (int) $user->id;
                    $isDescendant = false;
                    if (!$isUltimate && !$isOwnStore) {
                        $descendants = $user->getAllDescendants();
                        $descendantIds = $descendants->pluck('id')->toArray();
                        $isDescendant = in_array($store->owner_id, $descendantIds) || in_array($store->manager_id, $descendantIds);
                    }

                    if ($isUltimate || $isOwnStore || $isDescendant) {
                        $pivot = $product->stores()->where('store_id', $store->id)->first();
                        $currentStatus = $pivot ? $pivot->pivot->is_active : true;

                        $product->stores()->syncWithoutDetaching([
                            $store->id => [
                                'is_active' => !$currentStatus,
                            ]
                        ]);

                        return ResponseHelper::returnSuccessResponse(
                            ['is_active' => !$currentStatus],
                            $hash,
                            'Store-specific product status updated successfully'
                        );
                    }
                }
            }

            // PERMISSION CHECK: If not ultimate, must be the creator
            if (!$isUltimate && (int) $product->created_by !== (int) $user->id) {
                return ResponseHelper::returnUnauthorized('You can only modify products you created.');
            }

            $product->is_active = !$product->is_active;
            $product->save();
            
            return ResponseHelper::returnSuccessResponse(
                ['is_active' => $product->is_active],
                $hash,
                'Product status updated successfully'
            );
        } catch (Exception $e) {
            return ResponseHelper::returnError('Failed to update product status: ' . $e->getMessage());
        }
    }

    /**
     * Fuzzy-search global products by name so users can choose to import an existing
     * product into their store instead of creating a duplicate.
     */
    public function fuzzySearchByName(Request $request)
    {
        $user = Auth::user();
        if (!$user) {
            return ResponseHelper::returnUnauthorized();
        }

        $canCreateGlobal = ProductPermissions::isActionAllowed(UserActions::CreateProductGlobal);
        $canCreateForOwnStore = ProductPermissions::isActionAllowed(UserActions::CreateProductForOwnStore);
        if (!$canCreateGlobal && !$canCreateForOwnStore) {
            return ResponseHelper::returnUnauthorized();
        }

        $name = trim((string) $request->input('name', ''));
        $storeHash = $request->input('TargetStore');
        $limit = 10;

        if ($name === '') {
            return response()->json(['success' => true, 'data' => []]);
        }

        $normalized = strtolower($name);
        $tokens = array_values(array_filter(preg_split('/\s+/', $normalized) ?: [], fn ($t) => strlen($t) >= 2));

        $query = Product::query()
            ->select(['id', 'hashkey', 'name', 'price', 'unitname', 'category', 'subcategory', 'photourl', 'description'])
            ->where('is_active', 1);

        $query->where(function ($q) use ($normalized, $tokens) {
            $q->whereRaw('LOWER(name) LIKE ?', ['%' . $normalized . '%'])
              ->orWhereRaw('SOUNDEX(name) = SOUNDEX(?)', [$normalized]);
            foreach ($tokens as $tok) {
                $q->orWhereRaw('LOWER(name) LIKE ?', ['%' . $tok . '%']);
            }
        });

        $candidates = $query->limit(50)->get();

        // Score candidates by simple similarity; rank desc.
        $scored = $candidates->map(function ($p) use ($normalized) {
            $candidate = strtolower((string) $p->name);
            similar_text($normalized, $candidate, $percent);
            $contains = str_contains($candidate, $normalized) ? 15 : 0;
            $p->_score = $percent + $contains;
            return $p;
        })->filter(fn ($p) => $p->_score >= 45)
          ->sortByDesc('_score')
          ->values()
          ->take($limit);

        $alreadyInStoreIds = [];
        if ($storeHash) {
            $store = Store::where('hashkey', $storeHash)->first();
            if ($store) {
                $alreadyInStoreIds = $store->products()->pluck('prd_items.id')->toArray();
            }
        }

        $payload = $scored->map(function ($p) use ($alreadyInStoreIds) {
            return [
                'hashkey' => $p->hashkey,
                'name' => $p->name,
                'price' => $p->price,
                'unitname' => $p->unitname,
                'category' => $p->category,
                'subcategory' => $p->subcategory,
                'photourl' => $p->photourl,
                'description' => $p->description,
                'score' => round($p->_score, 1),
                'already_in_store' => in_array($p->id, $alreadyInStoreIds, true),
            ];
        });

        return response()->json(['success' => true, 'data' => $payload]);
    }
}



