<?php

namespace App\Http\Controllers;

use App\Http\Resources\ItemCollection;
use App\Models\Area;
use App\Models\BlockUser;
use App\Models\Blog;
use App\Models\Category;
use App\Models\Chat;
use App\Models\City;
use App\Models\ContactUs;
use App\Models\Country;
use App\Models\Currency;
use App\Models\CustomField;
use App\Models\Faq;
use App\Models\Favourite;
use App\Models\FeaturedItems;
use App\Models\FeatureSection;
use App\Models\Item;
use App\Models\ItemCustomFieldValue;
use App\Models\ItemImages;
use App\Models\ItemOffer;
use App\Models\JobApplication;
use App\Models\Language;
use App\Models\Notifications;
use App\Models\NumberOtp;
use App\Models\Package;
use App\Models\PaymentConfiguration;
use App\Models\PaymentTransaction;
use App\Models\ReportReason;
use App\Models\SellerRating;
use App\Models\SeoSetting;
use App\Models\Setting;
use App\Models\Slider;
use App\Models\SocialLogin;
use App\Models\State;
use App\Models\Tip;
use App\Models\User;
use App\Models\UserFcmToken;
use App\Models\UserPurchasedPackage;
use App\Models\UserReports;
use App\Models\VerificationField;
use App\Models\VerificationFieldValue;
use App\Models\VerificationRequest;
use App\Services\CachingService;
use App\Services\CurrencyFormatterService;
use App\Services\FileService;
use App\Services\HelperService;
use App\Services\NotificationService;
use App\Services\Payment\PaymentService;
use App\Services\ResponseService;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Unique;
use JsonException;
use Stichoza\GoogleTranslate\GoogleTranslate;
use Throwable;
use Twilio\Rest\Client as TwilioRestClient;

class ApiController extends Controller
{
    private string $uploadFolder;

    public function __construct()
    {
        $this->uploadFolder = 'item_images';
        if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) && ! empty($_SERVER['HTTP_AUTHORIZATION'])) {
            $this->middleware('auth:sanctum');
        }
    }

    public function getSystemSettings(Request $request)
    {
        try {
            $query = Setting::select(['id', 'name', 'value', 'type']); // include 'id' to support translation loading

            if (! empty($request->type)) {
                $query->where('name', $request->type);
            }

            $settings = $query->with('translations')->get();

            $tempRow = [];

            foreach ($settings as $row) {
                if (in_array($row->name, [
                    'account_holder_name',
                    'bank_name',
                    'account_number',
                    'ifsc_swift_code',
                    'bank_transfer_status',
                    'place_api_key',
                    'mail_password',
                    'mail_from_address',
                    'mail_username',
                    'twilio_account_sid',
                    'twilio_auth_token',
                    'twilio_my_phone_number',
                    'admin_user_email',
                    'admin_user_password',
                    'S3_aws_access_key_id',
                    's3_aws_secret_access_key',
                    's3_aws_default_region',
                    's3_aws_bucket',
                    's3_aws_url'
                ])) {
                    continue;
                }
                $tempRow[$row->name] = $row->translated_value ?? $row->value;
            }

            // --- determine current language ---
            $languageCode = $request->header('Content-Language') ?? app()->getLocale();
            $language = Language::where('code', $languageCode)->first();

            if (! $language) {
                $defaultLanguageCode = Setting::where('name', 'default_language')->value('value');
                $language = Language::where('code', $defaultLanguageCode)->first();
            }

            $tempRow['demo_mode'] = config('app.demo_mode');
            $tempRow['languages'] = CachingService::getLanguages();
            $tempRow['admin'] = User::role('Super Admin')->select(['name', 'profile'])->first();

            // 👇 add current language info
            $tempRow['current_language'] = $language?->code ?? app()->getLocale();

            ResponseService::successResponse(__('Data Fetched Successfully'), $tempRow);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getSystemSettings');
            ResponseService::errorResponse();
        }
    }

    public function userSignup(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'type' => 'required|in:email,google,phone,apple',
                'firebase_id' => 'nullable|string',
                'flag' => 'boolean',
                'platform_type' => 'nullable|in:android,ios',
                'region_code' => 'nullable|string',
                'country_code' => 'nullable|string',
                'mobile' => 'required_if:type,phone',
                'password' => 'nullable|string|min:6',
                'is_login' => 'boolean',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }

            $type = $request->type;
            $firebase_id = $request->firebase_id;
            if ($type == 'phone' && ! empty($request->password) && $request->boolean('is_login')) {

                $mobile = ltrim($request->mobile, '+');
                $countryCode = ltrim($request->country_code, '+');

                // 1️⃣ First: try with mobile + country code
               $mobileWithCode = $countryCode . $mobile;

                // First try strict match
                $user = User::where('type', 'phone')
                    ->where('mobile', $mobile)  
                    ->withTrashed()
                    ->first();
                
                    if (!$user) {
                        return ResponseService::errorResponse(
                            __('User not found. Please signup first.')
                        );
                    }

                    if ($user->deleted_at) {
                        return ResponseService::errorResponse(
                            __('User is deactivated. Please contact the administrator.')
                        );
                    }

                    // password exists check
                    if (empty($user->password)) {
                        return ResponseService::errorResponse(
                            __('Password is not set. Please set your password using the forgot password option.')
                        );
                    }

                    if (! Hash::check($request->password, $user->password)) {
                        return ResponseService::errorResponse(__('Invalid password.'));
                    }
            }
            $socialLogin = null;
            if (! empty($firebase_id)) {
                $socialLogin = SocialLogin::where('firebase_id', $firebase_id)
                    ->where('type', $type)
                    ->with('user', fn($q) => $q->withTrashed())
                    ->whereHas('user', fn($q) => $q->role('User'))
                    ->first();
            }

            if ($socialLogin && ! empty($socialLogin->user->deleted_at)) {
                return ResponseService::errorResponse(__('User is deactivated. Please Contact the administrator'));
            }
            if (empty($socialLogin)) {
                DB::beginTransaction();

                if ($request->type == 'phone') {
                    $unique['mobile'] = $request->mobile;
                } else {
                    $unique['email'] = $request->email;
                }

                $existingUser = User::withTrashed()->where($unique)->first();

                if ($existingUser && $existingUser->trashed()) {
                    return ResponseService::errorResponse(__('Your account has been deactivated.'), null, config('constants.RESPONSE_CODE.DEACTIVATED_ACCOUNT'));
                }

                $dataToUpdate = [
                    'region_code' => $request->region_code ?? null,
                    'profile' => $request->hasFile('profile') ? $request->file('profile')->store('user_profile', 'public') : $request->profile,
                ];
                if ($request->filled('password')) {
                    $dataToUpdate['password'] = Hash::make($request->password);
                } else {
                    $dataToUpdate['password'] = '';
                }

                $user = User::updateOrCreate($unique, array_merge($request->all(), $dataToUpdate));

                if (! empty($firebase_id)) {
                    SocialLogin::updateOrCreate(
                        ['type' => $type, 'user_id' => $user->id],
                        ['firebase_id' => $firebase_id]
                    );
                }
                $user->assignRole('User');
                Auth::login($user);
                $auth = User::find($user->id);
                DB::commit();
            } else {
                if ($socialLogin->user && ! empty($countryCode)) {
                    $socialLogin->user->update([
                        'country_code' => ltrim($countryCode, '+'),
                    ]);
                }
                // Social Login exists
                Auth::login($socialLogin->user);
                $auth = Auth::user();
            }
            if (! $auth->hasRole('User')) {
                ResponseService::errorResponse(__('Invalid Login Credentials'), null, config('constants.RESPONSE_CODE.INVALID_LOGIN'));
            }
            if (! empty($request->fcm_id)) {
                UserFcmToken::updateOrCreate(['fcm_token' => $request->fcm_id], ['user_id' => $auth->id, 'platform_type' => $request->platform_type, 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()]);
            }
            $auth->fcm_id = $request->fcm_id;
            if (! empty($request->registration)) {
                // If registration is passed then don't create token
                $token = null;
            } else {
                $token = $auth->createToken($auth->name ?? '')->plainTextToken;
            }
            if ($auth) {
                NotificationService::sendNewDeviceLoginEmail($auth, $request);
            }
            ResponseService::successResponse(__('User logged-in successfully'), $auth, ['token' => $token]);
        } catch (Throwable $th) {
            DB::rollBack();
            ResponseService::logErrorResponse($th, 'API Controller -> Signup');
            ResponseService::errorResponse();
        }
    }

    public function resetPassword(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'number' => 'required|string',
                'country_code' => 'required|string',
                'new_password' => 'required|string|min:6',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            $mobile = ltrim($request->number, '+');
            $countryCode = ltrim($request->country_code, '+');

            $mobileWithCode = $countryCode . $mobile;

            $user = User::where('type', 'phone')
                ->where('mobile', $mobile)->first();

            if (! $user) {
                ResponseService::errorResponse(__('User not found.'));
            }

            $user->password = Hash::make($request->new_password);
            $user->save();

            ResponseService::successResponse(__('Password reset successfully.'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> resetPassword');
            ResponseService::errorResponse();
        }
    }

    public function getUser(Request $request)
    {
        try {
            $auth = Auth::user();

            if (! $auth) {
                ResponseService::errorResponse(__('User not authenticated'));
            }

            if (! $auth->hasRole('User')) {
                ResponseService::errorResponse(__('Invalid User Role'));
            }
            $user = User::find($auth->id);

            ResponseService::successResponse(__('User fetched successfully'), $user);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> GetUser');
            ResponseService::errorResponse();
        }
    }

    public function updateProfile(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'name' => 'nullable|string',
                'profile' => 'nullable|mimes:jpg,jpeg,png|max:7168',
                'email' => 'nullable|email|unique:users,email,' . Auth::user()->id,
                'mobile' => [
                    'nullable',
                    Rule::unique('users')->ignore(Auth::user()->id)->where(function ($query) use ($request) {
                        return $query->where('country_code', '+' . $request->country_code);
                    }),
                ],
                'fcm_id' => 'nullable',
                'address' => 'nullable',
                'show_personal_details' => 'boolean',
                'country_code' => 'nullable|string',
                'region_code' => 'nullable|string',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }

            $app_user = Auth::user();
            // Email should not be updated when type is google.
            $data = $app_user->type == 'google' ? $request->except('email') : $request->all();

            if ($request->hasFile('profile')) {
                $data['profile'] = FileService::compressAndReplace($request->file('profile'), 'profile', $app_user->getRawOriginal('profile'));
            }

            if (! empty($request->fcm_id)) {
                UserFcmToken::updateOrCreate(['fcm_token' => $request->fcm_id], ['user_id' => $app_user->id, 'created_at' => Carbon::now(), 'updated_at' => Carbon::now()]);
            }
            $data['show_personal_details'] = $request->show_personal_details;

            $app_user->update($data);
            ResponseService::successResponse(__('Profile Updated Successfully'), $app_user);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> updateProfile');
            ResponseService::errorResponse();
        }
    }

    public function getPackage(Request $request)
    {
        $validator = Validator::make($request->toArray(), [
            'platform' => 'nullable|in:android,ios',
            'type' => 'nullable|in:advertisement,item_listing',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $packages = Package::with(['translations', 'categories', 'package_categories'])->where('status', 1);

            if (Auth::check()) {
                $packages = $packages->with('user_purchased_packages', function ($q) {
                    $q->onlyActive();
                });
            }

            if (isset($request->platform) && $request->platform == 'ios') {
                $packages->whereNotNull('ios_product_id');
            }

            if (! empty($request->type)) {
                $packages = $packages->where('type', $request->type);
            }
            $packages = $packages->orderBy('id', 'ASC')->get();

            $formatter = app(CurrencyFormatterService::class);

            $packages = $packages->map(function ($package) use ($formatter) {
                if (Auth::check()) {
                    $package['is_active'] = count($package->user_purchased_packages) > 0;
                } else {
                    $package['is_active'] = false;
                }

                // Only load package categories if package is not global
                if ($package->is_global != 1) {
                    // Add selected category IDs
                    $package['selected_category_ids'] = $package->package_categories->pluck('category_id')->toArray();

                    // Add categories data
                    $package['categories'] = $package->categories->map(function ($category) {
                        return [
                            'id' => $category->id,
                            'name' => $category->name,
                            'slug' => $category->slug ?? null,
                            'parent_category_id' => $category->parent_category_id ?? null,
                        ];
                    });
                } else {
                    $package['selected_category_ids'] = [];
                    $package['categories'] = [];
                }

                // Decode key_points JSON if it exists
                if (! empty($package->key_points)) {
                    $keyPoints = json_decode($package->key_points, true);
                    if (json_last_error() === JSON_ERROR_NONE && is_array($keyPoints)) {
                        $package['key_points'] = $keyPoints;
                    } else {
                        // If it's already an array or invalid JSON, keep as is
                        $package['key_points'] = is_array($package->key_points) ? $package->key_points : [];
                    }
                } else {
                    $package['key_points'] = [];
                }
                $iso_code = Setting::where('name', 'currency_iso_code')->value('value');
                $symbol = Setting::where('name', 'currency_symbol')->value('value');
                $position = Setting::where('name', 'currency_symbol_position')->value('value');

                $currency = (object) [
                    'iso_code' => $iso_code,
                    'symbol' => $symbol,
                    'symbol_position' => $position,
                ];

                // Formatted price fields
                $package['formatted_final_price'] = $formatter->formatPrice($package->final_price ?? 0, $currency);
                // If original/base price exists, format it too; fall back to final_price
                $basePrice = $package->price ?? $package->final_price ?? 0;
                $package['formatted_price'] = $formatter->formatPrice($basePrice, $currency);

                // If listing_duration_type is null, set it to 'package' and use package duration
                if (empty($package->listing_duration_type)) {
                    $package['listing_duration_type'] = 'package';
                    $package['listing_duration_days'] = $package->duration;
                }

                $package->user_purchased_packages = $package->user_purchased_packages->map(function ($purchased) use ($package) {
                    // 1. Calculate Duration/Days
                    if ($purchased->start_date && $purchased->end_date) {
                        $start = \Carbon\Carbon::parse($purchased->start_date);
                        $end = \Carbon\Carbon::parse($purchased->end_date);
                        $purchased['duration'] = $start->diffInDays($end);
                    } else {
                        $purchased['duration'] = "unlimited";
                    }

                    // 2. Map item_limit
                    $purchased['item_limit'] = $purchased->total_limit;

                    // 3. Fallback Logic for listing_duration_type & days
                    // Priority: Purchased Record -> Parent Package Record -> Default Setup
                    $purchased['listing_duration_type'] = $purchased->listing_duration_type
                        ?? $package->listing_duration_type
                        ?? 'package';

                    $days = $purchased->listing_duration_days ?? $package->listing_duration_days ?? $package->duration;

                    // If the final determined value is 0 or "0", return "unlimited"
                    $purchased['listing_duration_days'] = ($days == 0 && $days !== null) ? "unlimited" : $days;

                    return $purchased;
                });
                return $package;
            });
            ResponseService::successResponse(__('Data Fetched Successfully'), $packages);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getPackage');
            ResponseService::errorResponse();
        }
    }

    public function assignFreePackage(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'package_id' => 'required|exists:packages,id',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }

            $user = Auth::user();

            $package = Package::where(['final_price' => 0, 'id' => $request->package_id])->firstOrFail();
            $activePackage = UserPurchasedPackage::where(['package_id' => $request->package_id, 'user_id' => Auth::user()->id])->first();
            if (! empty($activePackage)) {
                ResponseService::errorResponse(__('You already have purchased this package'));
            }

            UserPurchasedPackage::create([
                'user_id' => $user->id,
                'package_id' => $request->package_id,
                'start_date' => Carbon::now(),
                'total_limit' => $package->item_limit == 'unlimited' ? null : $package->item_limit,
                'end_date' => $package->duration == 'unlimited' ? null : Carbon::now()->addDays($package->duration),
                'listing_duration_type' => $package->listing_duration_type,
                'listing_duration_days' => $package->listing_duration_days
            ]);
            ResponseService::successResponse(__('Package Purchased Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> assignFreePackage');
            ResponseService::errorResponse();
        }
    }

    public function getLimits(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'package_type' => 'required|in:item_listing,advertisement',
            ]);
            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            $setting = Setting::where('name', 'free_ad_listing')->first()['value'];
            if ($setting == 1 && $request->package_type != 'advertisement') {
                return ResponseService::successResponse(__('User is allowed to create Advertisement'));
            }
            $user_package = UserPurchasedPackage::onlyActive()->whereHas('package', function ($q) use ($request) {
                $q->where('type', $request->package_type);
            })->count();
            if ($user_package > 0) {
                ResponseService::successResponse(__('User is allowed to create Advertisement'));
            }
            ResponseService::errorResponse(__('User is not allowed to create Advertisement'), $user_package);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getLimits');
            ResponseService::errorResponse();
        }
    }

    public function getCurrencies(Request $request)
    {
        try {
            $countryName = $request->query('country');

            $selectedCurrencyId = null;

            // If country param is passed
            if ($countryName) {
                $country = Country::where('name', $countryName)
                    ->select('id', 'currency_id')
                    ->first();

                $selectedCurrencyId = $country?->id;
            }

            $currencies = Currency::select(
                'id',
                'iso_code',
                'symbol',
                'symbol_position',
                'country_id'
            )
                ->orderBy('iso_code')
                ->get()
                ->map(function ($currency) use ($selectedCurrencyId) {
                    return [
                        'id' => $currency->id,
                        'iso_code' => $currency->iso_code,
                        'symbol' => $currency->symbol,
                        'position' => $currency->symbol_position,
                        'selected' => $selectedCurrencyId == $currency->country_id ? 1 : 0,
                    ];
                });
            ResponseService::successResponse(__('Currency fetched Successfully'), $currencies);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCurrencies');
            ResponseService::errorResponse();
        }
    }

    public function addItem(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'name' => 'required',
                'category_id' => 'required|integer',
                'description' => 'required',
                'latitude' => 'required',
                'longitude' => 'required',
                'address' => 'required',
                'contact' => 'nullable|numeric',
                'show_only_to_premium' => 'required|boolean',
                'video_link' => 'nullable|url',
                'gallery_images' => 'nullable|array|min:1',
                'gallery_images.*' => 'nullable|mimes:jpeg,png,jpg|max:7168',
                'image' => 'required|mimes:jpeg,png,jpg|max:7168',
                'country' => 'required',
                'state' => 'nullable',
                'city' => 'required',
                'custom_field_files' => 'nullable|array',
                'custom_field_files.*' => 'nullable|mimes:jpeg,png,jpg,pdf,doc|max:7168',
                'slug' => [
                    'nullable',
                    'regex:/^(?!-)(?!.*--)(?!.*-$)(?!-$)[a-z0-9-]+$/',
                ],
                'region_code' => 'nullable|string',
                'currency_id' => 'required|exists:currencies,id',
                'all_category_ids' => 'nullable|array',
                'all_category_ids.*' => 'integer|exists:categories,id',
            ]);
            $translations = json_decode($request->input('translations', '{}'), true, 512, JSON_THROW_ON_ERROR);
            if (! empty($translations)) {
                foreach ($translations as $languageId => $translation) {
                    Validator::make($translation, [
                        'name' => 'required|string|max:255',
                        'slug' => 'nullable|regex:/^[a-z0-9-]+$/',
                        'description' => 'nullable|string',
                        'address' => 'nullable|string',
                        'video_link' => 'nullable|url',
                        'rejected_reason' => 'nullable|string',
                        'admin_edit_reason' => 'nullable|string',
                    ])->validate();
                }
            }
            $category = Category::findOrFail($request->category_id);

            $isJobCategory = $category->is_job_category;
            $isPriceOptional = $category->price_optional;

            if ($isJobCategory || $isPriceOptional) {
                $validator = Validator::make($request->all(), [
                    'min_salary' => 'nullable|numeric|min:0',
                    'max_salary' => 'nullable|numeric|gte:min_salary',
                ]);
            } else {
                $validator = Validator::make($request->all(), [
                    'price' => 'required|numeric|min:0',
                ]);
            }
            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }

            DB::beginTransaction();
            $user = Auth::user();
            $free_ad_listing = Setting::where('name', 'free_ad_listing')->value('value') ?? 0;
            $auto_approve_item = Setting::where('name', 'auto_approve_item')->value('value') ?? 0;

            if ($auto_approve_item == 1 || $user->auto_approve_item == 1) {
                $status = 'approved';
            } else {
                $status = 'review';
            }

            // Get all active packages for the user
            $user_packages = null;
            $selectedPackageId = null;
            $selectedUserPackage = null;

            // Only check package if free_ad_listing is not enabled
            if ($free_ad_listing != 1) {
                // Get ALL active packages for the user
                $user_packages = UserPurchasedPackage::onlyActive()
                    ->whereHas('package', static function ($q) {
                        $q->where('type', 'item_listing');
                    })
                    ->where('user_id', $user->id)
                    ->with('package.package_categories')
                    ->get();

                if ($user_packages->isEmpty()) {
                    DB::rollBack();
                    ResponseService::errorResponse(__('No Active Package found for Advertisement Creation'));
                }

                // Get all_category_ids from request (should contain category and all parent categories)
               $allCategoryIds = $request->input('all_category_ids', []);

                // If it comes as comma-separated string, convert to array
                if (is_string($allCategoryIds)) {
                    $allCategoryIds = array_filter(
                        array_map('intval', explode(',', $allCategoryIds))
                    );
                }

                // Ensure it's always an array
                if (! is_array($allCategoryIds)) {
                    $allCategoryIds = [];
                }

                // If all_category_ids not provided, build it from category_id
                if (empty($allCategoryIds) && $request->category_id) {
                    $allCategoryIds = [$request->category_id];
                    $currentCategoryId = $request->category_id;

                    // Traverse up the parent chain
                    while ($currentCategoryId) {
                        $parentCategory = Category::find($currentCategoryId);
                        if ($parentCategory && $parentCategory->parent_category_id) {
                            $allCategoryIds[] = $parentCategory->parent_category_id;
                            $currentCategoryId = $parentCategory->parent_category_id;
                        } else {
                            break;
                        }
                    }
                    $allCategoryIds = array_unique($allCategoryIds);
                }

                // Check for global package first
                $globalPackage = $user_packages->firstWhere(function ($userPackage) {
                    return $userPackage->package && $userPackage->package->is_global == 1;
                });

                if ($globalPackage) {
                    // Use global package
                    $selectedPackageId = $globalPackage->package_id;
                    $selectedUserPackage = $globalPackage;
                } else {
                    // No global package, check if any package contains any category from all_category_ids
                    $matchingPackage = null;

                    foreach ($user_packages as $user_package) {
                        if ($user_package->package && $user_package->package->is_global != 1) {
                            $packageCategoryIds = $user_package->package->package_categories
                                ->pluck('category_id')
                                ->toArray();

                            // Check if any category from all_category_ids is in this package
                            $hasMatchingCategory = ! empty(array_intersect($allCategoryIds, $packageCategoryIds));

                            if ($hasMatchingCategory) {
                                $matchingPackage = $user_package;
                                break;
                            }
                        }
                    }

                    if ($matchingPackage) {
                        $selectedPackageId = $matchingPackage->package_id;
                        $selectedUserPackage = $matchingPackage;
                    } else {
                        DB::rollBack();
                        ResponseService::errorResponse(__('Selected category is not available in your package'));
                    }
                }
            }

            // Increment used_limit for the selected package
            if ($selectedUserPackage) {
                $selectedUserPackage->used_limit++;
                $selectedUserPackage->save();
            }

            $slug = trim($request->input('slug') ?? '');
            $slug = preg_replace('/[^a-z0-9]+/i', '-', strtolower($slug));
            $slug = trim($slug, '-');
            if (empty($slug)) {
                $slug = HelperService::generateRandomSlug();
            }
            $uniqueSlug = HelperService::generateUniqueSlug(new Item, $slug);

            // Calculate expiry date based on package listing duration
            $package = $selectedPackageId ? Package::find($selectedPackageId) : null;
            $expiryDate = HelperService::calculateItemExpiryDate($package, $selectedUserPackage);

            $data = [
                ...$request->all(),
                'name' => $request->name,
                'slug' => $uniqueSlug,
                'status' => $status,
                'active' => 'deactive',
                'user_id' => $user->id,
                'package_id' => $selectedPackageId ?? null,
                'expiry_date' => $expiryDate,
            ];
            if ($request->hasFile('image')) {
                $data['image'] = FileService::compressAndUpload($request->file('image'), $this->uploadFolder, true);
            }
            $item = Item::create($data);
            if (! empty($translations)) {
                foreach ($translations as $languageId => $translationData) {
                    // Optional: Check if language ID exists
                    if (Language::where('id', $languageId)->exists()) {
                        $item->translations()->create([
                            'language_id' => $languageId,
                            'name' => $translationData['name'],
                            'description' => $translationData['description'] ?? '',
                            'address' => $translationData['address'] ?? '',
                            'rejected_reason' => $translationData['rejected_reason'] ?? null,
                            'admin_edit_reason' => $translationData['admin_edit_reason'] ?? null,
                        ]);
                    }
                }
            }

            if ($request->hasFile('gallery_images')) {
                $galleryImages = [];
                foreach ($request->file('gallery_images') as $file) {
                    $galleryImages[] = [
                        'image' => FileService::compressAndUpload($file, $this->uploadFolder, true),
                        'item_id' => $item->id,
                        'created_at' => time(),
                        'updated_at' => time(),
                    ];
                }

                if (count($galleryImages) > 0) {
                    ItemImages::insert($galleryImages);
                }
            }
            if ($request->custom_fields) {
                $itemCustomFieldValues = [];
                foreach (json_decode($request->custom_fields, true, 512, JSON_THROW_ON_ERROR) as $key => $custom_field) {
                    $itemCustomFieldValues[] = [
                        'item_id' => $item->id,
                        'language_id' => 1,
                        'custom_field_id' => $key,
                        'value' => json_encode($custom_field, JSON_THROW_ON_ERROR),
                        'created_at' => time(),
                        'updated_at' => time(),
                    ];
                }

                if (count($itemCustomFieldValues) > 0) {
                    ItemCustomFieldValue::insert($itemCustomFieldValues);
                }
            }

            if ($request->custom_field_files) {
                $itemCustomFieldValues = [];
                foreach ($request->custom_field_files as $key => $file) {
                    $itemCustomFieldValues[] = [
                        'item_id' => $item->id,
                        'language_id' => 1,
                        'custom_field_id' => $key,
                        'value' => ! empty($file) ? FileService::upload($file, 'custom_fields_files') : '',
                        'created_at' => time(),
                        'updated_at' => time(),
                    ];
                }

                if (count($itemCustomFieldValues) > 0) {
                    ItemCustomFieldValue::insert($itemCustomFieldValues);
                }
            }
            // Handle Translated Custom Field Values
            if ($request->has('custom_field_translations')) {
                $customFieldTranslations = $request->input('custom_field_translations');

                if (! is_array($customFieldTranslations)) {
                    $customFieldTranslations = html_entity_decode($customFieldTranslations);
                    $customFieldTranslations = json_decode($customFieldTranslations, true, 512, JSON_THROW_ON_ERROR);
                }

                $translatedEntries = [];

                foreach ($customFieldTranslations as $languageId => $fieldsByCustomField) {
                    foreach ($fieldsByCustomField as $customFieldId => $translatedValue) {
                        $translatedEntries[] = [
                            'item_id' => $item->id,
                            'custom_field_id' => $customFieldId,
                            'language_id' => $languageId,
                            'value' => json_encode($translatedValue, JSON_THROW_ON_ERROR),
                            'created_at' => now(),
                            'updated_at' => now(),
                        ];
                    }
                }

                if (! empty($translatedEntries)) {
                    ItemCustomFieldValue::insert($translatedEntries);
                }
            }

            // Optimize: Only load essential relationships to prevent memory timeout
            $result = Item::with([
                'user:id,name,email,mobile,profile,country_code',
                'category:id,name,image,is_job_category,price_optional',
                'gallery_images:id,image,item_id',
                'area:id,name',
                'translations',
            ])
                ->where('items.id', $item->id)
                ->first();

            // Load expensive relationships only if needed (lazy loading) to prevent memory timeout
            if ($result) {
                $result->loadMissing(['featured_items', 'favourites']);
                // Only load custom fields if they exist (avoid loading all nested translations)
                if ($result->item_custom_field_values()->exists()) {
                    $result->load('item_custom_field_values.custom_field:id,name,type');
                }
            }

            $result = new ItemCollection(collect([$result]));

            DB::commit();
            ResponseService::successResponse(__('Advertisement Added Successfully'), $result);
        } catch (Throwable $th) {
            DB::rollBack();
            ResponseService::logErrorResponse($th, 'API Controller -> addItem');
            ResponseService::errorResponse();
        }
    }

    public function getItem(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'limit' => 'nullable|integer',
            'offset' => 'nullable|integer',
            'id' => 'nullable',
            'custom_fields' => 'nullable',
            'slug' => 'nullable|string',
            'category_id' => 'nullable',
            'user_id' => 'nullable',
            'min_price' => 'nullable',
            'max_price' => 'nullable',
            'sort_by' => 'nullable|in:new-to-old,old-to-new,price-high-to-low,price-low-to-high,popular_items',
            'posted_since' => 'nullable|in:all-time,today,within-1-week,within-2-week,within-1-month,within-3-month',
            'current_page' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            // TODO : need to simplify this whole module
            $maxPrice = Item::max('price') ?? 0;

            $sql = Item::with(
                'user:id,name,email,mobile,profile,created_at,is_verified,show_personal_details,country_code',
                'category:id,name,image,is_job_category,price_optional',
                'gallery_images:id,image,item_id',
                'featured_items',
                'favourites',
                'item_custom_field_values.custom_field.translations',
                'area:id,name',
                'job_applications',
                'translations',
                'currency',

            )
                ->withCount('featured_items')
                ->withCount('job_applications')
                ->select('items.*')
                ->whereHas('category', function ($q) {
                    $q->where('status', '!=', 0)
                        ->where(function ($query) {
                            // Either no parent or parent status != 0
                            $query->whereDoesntHave('parent') // no parent category
                                ->orWhereHas('parent', function ($q2) {
                                    $q2->where('status', '!=', 0);
                                });
                        });
                })
                ->when($request->id, function ($sql) use ($request) {
                    $sql->where('items.id', $request->id);
                })->when(($request->category_id), function ($sql) use ($request) {
                    $category = Category::where('id', $request->category_id)->with('children')->first();
                    $categoryIDS = HelperService::findAllCategoryIds(collect([$category]));

                    return $sql->whereIn('category_id', $categoryIDS);
                })->when(($request->category_slug), function ($sql) use ($request) {
                    $category = Category::where('slug', $request->category_slug)->with('children')->first();
                    $categoryIDS = HelperService::findAllCategoryIds(collect([$category]));

                    return $sql->whereIn('category_id', $categoryIDS);
                })->when((isset($request->min_price) || isset($request->max_price)), function ($sql) use ($request, $maxPrice) {
                    $min_price = $request->min_price ?? 0;
                    $max_price = $request->max_price ?? $maxPrice;

                    return $sql->whereBetween('price', [$min_price, $max_price]);
                })->when($request->posted_since, function ($sql) use ($request) {
                    return match ($request->posted_since) {
                        // Qualify column to avoid ambiguity once joins are applied (e.g. featured_items)
                        'today' => $sql->whereDate('items.created_at', '>=', now()),
                        'within-1-week' => $sql->whereDate('items.created_at', '>=', now()->subDays(7)),
                        'within-2-week' => $sql->whereDate('items.created_at', '>=', now()->subDays(14)),
                        'within-1-month' => $sql->whereDate('items.created_at', '>=', now()->subMonths()),
                        'within-3-month' => $sql->whereDate('items.created_at', '>=', now()->subMonths(3)),
                        default => $sql
                    };
                })->when($request->area_id, function ($sql) use ($request) {
                    return $sql->where('area_id', $request->area_id);
                })->when($request->user_id, function ($sql) use ($request) {
                    return $sql->where('user_id', $request->user_id);
                })->when($request->slug, function ($sql) use ($request) {
                    return $sql->where('slug', $request->slug);
                });

            if ($request->sort_by == 'new-to-old') {
                $sql->orderBy('items.id', 'DESC');
            } elseif ($request->sort_by == 'old-to-new') {
                $sql->orderBy('items.id', 'ASC');
            } elseif ($request->sort_by == 'price-high-to-low') {
                $sql->orderByRaw('
                    COALESCE(price, max_salary, min_salary, 0) DESC
                ');
            } elseif ($request->sort_by == 'price-low-to-high') {
                $sql->orderByRaw('
                    COALESCE(price, min_salary, max_salary, 0) ASC
                ');
            } elseif ($request->sort_by == 'popular_items') {
                $sql->orderBy('clicks', 'DESC');
            } else {
                $sql->orderBy('items.id', 'DESC');
            }

            // Status
            if (! empty($request->status)) {
                if (in_array($request->status, ['review', 'approved', 'rejected', 'sold out', 'soft rejected', 'permanent rejected', 'resubmitted'])) {
                    $sql->where('status', $request->status)->getNonExpiredItems()->whereNull('deleted_at');
                } elseif ($request->status == 'inactive') {
                    // If status is inactive then display only trashed items
                    $sql->onlyTrashed()->getNonExpiredItems();
                } elseif ($request->status == 'featured') {
                    // If status is featured then display only featured items
                    $sql->where('status', 'approved')->has('featured_items')->getNonExpiredItems();
                } elseif ($request->status == 'expired') {
                    $sql->whereNotNull('expiry_date')
                        ->where('expiry_date', '<', Carbon::now())->whereNull('deleted_at');
                }
            }

            // Feature Section Filtration
            // Only apply feature section filters if user hasn't provided conflicting filters
            // User filters should override feature section defaults
            if (! empty($request->featured_section_id) || ! empty($request->featured_section_slug)) {
                if (! empty($request->featured_section_id)) {
                    $featuredSection = FeatureSection::findOrFail($request->featured_section_id);
                } else {
                    $featuredSection = FeatureSection::where('slug', $request->featured_section_slug)->firstOrFail();
                }

                // Check if user has provided filters that should override feature section filters
                $hasUserPriceFilter = isset($request->min_price) || isset($request->max_price);
                $hasUserSortFilter = ! empty($request->sort_by);
                $hasUserCategoryFilter = ! empty($request->category_id) || ! empty($request->category_slug);

                // Apply feature section filters only if user hasn't provided conflicting filters
                $sql = match ($featuredSection->filter) {
                    'price_criteria' => $hasUserPriceFilter
                        ? $sql // User price filter already applied, skip feature section price filter
                        // : $sql->whereBetween('price', [$featuredSection->min_price, $featuredSection->max_price]),
                        : $sql->where(function ($query) use ($featuredSection) {
                            $query->whereBetween('price', [$featuredSection->min_price, $featuredSection->max_price])
                                ->orWhere(function ($q) use ($featuredSection) {
                                    $q->whereBetween('min_salary', [$featuredSection->min_price, $featuredSection->max_price])
                                        ->whereBetween('max_salary', [$featuredSection->min_price, $featuredSection->max_price]);
                                });
                        }),
                    'most_viewed' => $hasUserSortFilter
                        ? $sql // User sort already applied, skip feature section sort
                        : $sql->reorder()->orderBy('clicks', 'DESC'),

                    'category_criteria' => $hasUserCategoryFilter
                        ? $sql // User category filter already applied, skip feature section category filter
                        : (static function () use ($featuredSection, $sql) {
                            $category = Category::whereIn('id', explode(',', $featuredSection->value))->with('children')->get();
                            $categoryIDS = HelperService::findAllCategoryIds($category);

                            return $sql->whereIn('category_id', $categoryIDS);
                        })(),

                    'most_liked' => $hasUserSortFilter
                        ? $sql // User sort already applied, skip feature section sort
                        : $sql->reorder()->withCount('favourites'), // ->orderBy('favourites_count', 'DESC'),

                    'featured_ads' => $sql->where('status', 'approved')->has('featured_items')->getNonExpiredItems(),
                };
            }

            if (! empty($request->search)) {
                $sql->search($request->search);
            }

            function removeBackslashesRecursive($data)
            {
                $cleaned = [];
                foreach ($data as $key => $value) {
                    $cleanKey = stripslashes($key);
                    if (is_array($value)) {
                        $cleaned[$cleanKey] = removeBackslashesRecursive($value);
                    } else {
                        $cleaned[$cleanKey] = stripslashes($value);
                    }
                }

                return $cleaned;
            }
            // Optimize custom fields filtering - use whereHas instead of joins for better performance
            $cleanedParameters = removeBackslashesRecursive($request->all());
            if (! empty($cleanedParameters['custom_fields'])) {
                $customFields = $cleanedParameters['custom_fields'];
                $sql->whereHas('item_custom_field_values', function ($query) use ($customFields) {
                    $query->whereIn('custom_field_id', array_keys($customFields));
                    foreach ($customFields as $customFieldId => $value) {
                        $query->where(function ($q) use ($customFieldId, $value) {
                            if (is_array($value)) {
                                foreach ($value as $arrayValue) {
                                    $q->orWhere(function ($subQ) use ($customFieldId, $arrayValue) {
                                        $subQ->where('custom_field_id', $customFieldId)
                                            ->where('value', 'LIKE', '%' . trim($arrayValue) . '%');
                                    });
                                }
                            } else {
                                $q->orWhere(function ($subQ) use ($customFieldId, $value) {
                                    $subQ->where('custom_field_id', $customFieldId)
                                        ->where('value', 'LIKE', '%' . trim($value) . '%');
                                });
                            }
                        });
                    }
                }, '>=', count($customFields));
            }

            if (Auth::check()) {
                $sql->with(['item_offers' => function ($q) {
                    $q->where('buyer_id', Auth::user()->id);
                }, 'user_reports' => function ($q) {
                    $q->where('user_id', Auth::user()->id);
                }]);

                $currentURI = explode('?', $request->getRequestUri(), 2);

                if ($currentURI[0] == '/api/my-items') { // TODO: This if condition is temporary fix. Need something better
                    $sql->where(['user_id' => Auth::user()->id])->withTrashed();
                } else {
                    $sql->where('status', 'approved')->has('user')->onlyNonBlockedUsers()->getNonExpiredItems();
                }
            } else {
                //  Other users should only get approved items
                $sql->where('status', 'approved')->getNonExpiredItems();
            }

            // Helper function to apply auth filters
            $applyAuthFilters = function ($query) use ($request) {
                if (Auth::check()) {
                    $query->with(['item_offers' => function ($q) {
                        $q->where('buyer_id', Auth::user()->id);
                    }, 'user_reports' => function ($q) {
                        $q->where('user_id', Auth::user()->id);
                    }]);

                    $currentURI = explode('?', $request->getRequestUri(), 2);
                    if ($currentURI[0] == '/api/my-items') {
                        $query->where(['user_id' => Auth::user()->id])->withTrashed();
                    } else {
                        $query->where('status', 'approved')->has('user')->onlyNonBlockedUsers()->getNonExpiredItems();
                    }
                } else {
                    $query->where('status', 'approved')->getNonExpiredItems();
                }

                return $query;
            };

            // Apply location filters using shared function
            $locationResult = HelperService::applyLocationFilters($sql, $request, $applyAuthFilters);
            $sql = $locationResult['query'];
            $locationMessage = $locationResult['message'];

            $baseQuery = clone $sql;

            // FEATURED QUERY
            $featuredQuery = clone $baseQuery;
            $featuredQuery
                ->whereHas('featured_items', function ($q) {
                    $q->whereDate('start_date', '<=', now())
                        ->where(function ($q) {
                            $q->whereNull('end_date')
                                ->orWhereDate('end_date', '>=', now());
                        });
                })
                ->join('featured_items as fi', 'fi.item_id', '=', 'items.id')
                ->orderBy('fi.created_at', 'DESC')
                // IMPORTANT: do not override select() here because location filters may have added
                // `distance` via selectRaw(... AS distance). Overriding select would remove it and
                // break ORDER BY distance with "Unknown column 'distance'".
                ->addSelect('items.*');

            // NORMAL QUERY
            $normalQuery = clone $baseQuery;
            $normalQuery
                ->whereDoesntHave('featured_items', function ($q) {
                    $q->whereDate('start_date', '<=', now())
                        ->where(function ($q) {
                            $q->whereNull('end_date')
                                ->orWhereDate('end_date', '>=', now());
                        });
                })
                ->orderBy('items.created_at', 'DESC');

            // Cast to integers to prevent "string - int" error
            $limit = (int) ($request->limit ?? 10);
            $page = (int) ($request->page ?? 1);

            $totalFeatured = (clone $featuredQuery)->distinct('items.id')->count('items.id');
            $totalNormal = (clone $normalQuery)->count();
            $totalItems = $totalFeatured + $totalNormal;

            // Ensure totalPages is at least 1 to avoid division by zero
            $totalPages = (int) max(1, ceil($totalItems / $limit));

            // Distribute featured items across pages
            $featuredPerPage = (int) ceil($totalFeatured / $totalPages);

            // Now subtraction will work because both are integers
            $normalPerPage = $limit - $featuredPerPage;

            if ($normalPerPage < 0) {
                $normalPerPage = 0;
            }

            $featuredOffset = ($page - 1) * $featuredPerPage;
            $normalOffset = ($page - 1) * $normalPerPage;

            if ($normalPerPage < 0) {
                $normalPerPage = 0;
            }

            $featuredItems = $featuredQuery
                ->skip($featuredOffset)
                ->take($featuredPerPage)
                ->get();

            $normalItems = $normalQuery
                ->skip($normalOffset)
                ->take($normalPerPage)
                ->get();

            $items = $featuredItems->merge($normalItems);

            $paginator = new LengthAwarePaginator(
                $items,
                $totalItems,
                $limit,
                $page,
                [
                    'path' => request()->url(),
                    'query' => request()->query(),
                ]
            );

            // Execute query and get results
            if (! empty($request->id)) {
                /*
                 * Collection does not support first OR find method's result as of now. It's a part of R&D
                 * So currently using this shortcut method get() to fetch the first data
                 */
                $result = $sql->get();
                // dd($result);
                if (count($result) == 0) {
                    ResponseService::errorResponse(__('No item Found'));
                }
            } else {
                if (! empty($request->limit)) {
                    $result = $sql->paginate($request->limit);
                } else {
                    $result = $sql->paginate();
                }
            }

            // Prepare response with location message if applicable
            $responseData = new ItemCollection($paginator);
            // Use location message if available, otherwise use default success message
            $responseMessage = ! empty($locationMessage) ? $locationMessage : __('Advertisement Fetched Successfully');

            // return response()->json($responseData);

            ResponseService::successResponse($responseMessage, $responseData);
            // if (!empty($request->id)) {
            //     /*
            //      * Collection does not support first OR find method's result as of now. It's a part of R&D
            //      * So currently using this shortcut method get() to fetch the first data
            //      */
            //     $result = $sql->get();
            //     if (count($result) == 0) {
            //         ResponseService::errorResponse(__('No item Found'));
            //     }
            // } else {
            //     if (!empty($request->limit)) {
            //         $result = $sql->paginate($request->limit);
            //     } else {
            //         $result = $sql->paginate();
            //     }

            // }
            //                // Add three regular items
            //                for ($i = 0; $i < 3 && $regularIndex < $regularItemCount; $i++) {
            //                    $items->push($regularItems[$regularIndex]);
            //                    $regularIndex++;
            //                }
            //
            //                // Add one featured item if available
            //                if ($featuredIndex < $featuredItemCount) {
            //                    $items->push($featuredItems[$featuredIndex]);
            //                    $featuredIndex++;
            //                }
            //            }
            // Return success response with the fetched items

            // ResponseService::successResponse(__('Advertisement Fetched Successfully'), new ItemCollection($result));

        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getItem');
            ResponseService::errorResponse();
        }
    }

    public function updateItem(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id' => 'required',
            'name' => 'nullable',
            'slug' => [
                'nullable',
                'regex:/^(?!-)(?!.*--)(?!.*-$)(?!-$)[a-z0-9-]+$/',
            ],
            'price' => 'nullable',
            'description' => 'nullable',
            'latitude' => 'nullable',
            'longitude' => 'nullable',
            'address' => 'nullable',
            'contact' => 'nullable',
            'image' => 'nullable|mimes:jpeg,jpg,png|max:7168',
            'custom_fields' => 'nullable',
            'custom_field_files' => 'nullable|array',
            'custom_field_files.*' => 'nullable|mimes:jpeg,png,jpg,pdf,doc|max:7168',
            'gallery_images' => 'nullable|array',
            'currency_id' => 'nullable|exists:currencies,id',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        DB::beginTransaction();

        try {

            $item = Item::owner()->findOrFail($request->id);
            $auto_approve_item = Setting::where('name', 'auto_approve_edited_item')->value('value') ?? 0;
            if ($auto_approve_item == 1) {
                $status = 'approved';
            } else {
                $status = 'review';
            }
            $slugInput = $request->input('slug') ?? '';
            $slug = preg_replace('/[^a-z0-9]+/i', '-', strtolower(trim($slugInput)));
            $slug = trim($slug, '-');

            // If slug is empty after cleaning, use existing item slug
            if (empty($slug)) {
                $slug = $item->slug;
            }

            // Generate unique slug
            $uniqueSlug = HelperService::generateUniqueSlug(new Item, $slug, $request->id);

            $data = $request->all();
            $data['slug'] = $uniqueSlug;
            $data['status'] = $status;
            if ($request->hasFile('image')) {
                $data['image'] = FileService::compressAndReplace($request->file('image'), $this->uploadFolder, $item->getRawOriginal('image'), true);
            }

            $item->update($data);
            // Update or create item translations
            $translations = json_decode($request->input('translations', '{}'), true, 512, JSON_THROW_ON_ERROR);
            if (! empty($translations)) {
                foreach ($translations as $languageId => $translationData) {
                    if (Language::where('id', $languageId)->exists()) {
                        $item->translations()->updateOrCreate(
                            ['language_id' => $languageId],
                            [
                                'name' => $translationData['name'],
                                'description' => $translationData['description'] ?? '',
                                'address' => $translationData['address'] ?? '',
                                'rejected_reason' => $translationData['rejected_reason'] ?? null,
                                'admin_edit_reason' => $translationData['admin_edit_reason'] ?? null,
                            ]
                        );
                    }
                }
            }

            // Update Custom Field values for item
            if ($request->custom_fields) {
                $itemCustomFieldValues = [];
                foreach (json_decode($request->custom_fields, true, 512, JSON_THROW_ON_ERROR) as $key => $custom_field) {
                    $itemCustomFieldValues[] = [
                        'item_id' => $item->id,
                        'custom_field_id' => $key,
                        'value' => json_encode($custom_field, JSON_THROW_ON_ERROR),
                        'updated_at' => time(),
                    ];
                }

                if (count($itemCustomFieldValues) > 0) {
                    ItemCustomFieldValue::upsert($itemCustomFieldValues, ['item_id', 'custom_field_id'], ['value', 'updated_at']);
                }
            }

            // Add new gallery images
            if ($request->hasFile('gallery_images')) {
                $galleryImages = [];
                foreach ($request->file('gallery_images') as $file) {
                    $galleryImages[] = [
                        'image' => FileService::compressAndUpload($file, $this->uploadFolder, true),
                        'item_id' => $item->id,
                        'created_at' => time(),
                        'updated_at' => time(),
                    ];
                }
                if (count($galleryImages) > 0) {
                    ItemImages::insert($galleryImages);
                }
            }

            if ($request->custom_field_files) {
                $itemCustomFieldValues = [];
                foreach ($request->custom_field_files as $key => $file) {
                    $value = ItemCustomFieldValue::where(['item_id' => $item->id, 'custom_field_id' => $key])->first();
                    if (! empty($value)) {
                        $file = FileService::replace($file, 'custom_fields_files', $value->getRawOriginal('value'));
                    } else {
                        $file = '';
                    }

                    $itemCustomFieldValues[] = [
                        'item_id' => $item->id,
                        'language_id' => 1,
                        'custom_field_id' => $key,
                        'value' => $file,
                        'updated_at' => time(),
                    ];
                }

                if (count($itemCustomFieldValues) > 0) {
                    ItemCustomFieldValue::updateOrCreate(
                        ['item_id' => $item->id, 'custom_field_id' => $key],
                        ['value' => $file, 'language_id' => 1, 'updated_at' => time()]
                    );
                }
            }
            // Update or insert custom field translations
            if ($request->has('custom_field_translations')) {
                $customFieldTranslations = $request->input('custom_field_translations');

                if (! is_array($customFieldTranslations)) {
                    $customFieldTranslations = html_entity_decode($customFieldTranslations);
                    $customFieldTranslations = json_decode($customFieldTranslations, true, 512, JSON_THROW_ON_ERROR);
                }
                $translatedEntries = [];

                foreach ($customFieldTranslations as $languageId => $fieldsByCustomField) {
                    foreach ($fieldsByCustomField as $customFieldId => $translatedValue) {
                        $translatedEntries[] = [
                            'item_id' => $item->id,
                            'custom_field_id' => $customFieldId,
                            'language_id' => $languageId,
                            'value' => json_encode($translatedValue, JSON_THROW_ON_ERROR),
                            'updated_at' => now(),
                            'created_at' => now(),
                        ];
                    }
                }

                if (! empty($translatedEntries)) {
                    // Ensure combination is unique
                    ItemCustomFieldValue::upsert(
                        $translatedEntries,
                        ['item_id', 'custom_field_id', 'language_id'], // unique keys
                        ['value', 'updated_at']
                    );
                }
            }

            // Delete gallery images
            if (! empty($request->delete_item_image_id)) {
                $item_ids = explode(',', $request->delete_item_image_id);
                foreach (ItemImages::whereIn('id', $item_ids)->get() as $itemImage) {
                    FileService::delete($itemImage->getRawOriginal('image'));
                    $itemImage->delete();
                }
            }

            $result = Item::with('user:id,name,email,mobile,profile,country_code', 'category:id,name,image,is_job_category,price_optional', 'gallery_images:id,image,item_id', 'featured_items', 'favourites', 'item_custom_field_values.custom_field.translations', 'area', 'translations')->where('items.id', $item->id)->get();
            /*
               * Collection does not support first OR find method's result as of now. It's a part of R&D
               * So currently using this shortcut method
              */
            $result = new ItemCollection($result);

            DB::commit();
            ResponseService::successResponse(__('Advertisement Fetched Successfully'), $result);
        } catch (Throwable $th) {
            DB::rollBack();
            ResponseService::logErrorResponse($th, 'API Controller -> updateItem');
            ResponseService::errorResponse();
        }
    }

    public function deleteItem(Request $request)
    {
        try {
            // Validation rules
            $rules = [
                'item_id' => 'nullable|exists:items,id',
                'item_ids' => 'nullable|string', // comma-separated IDs
            ];

            $validator = Validator::make($request->all(), $rules);
            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }

            // Normalize IDs
            $itemIds = [];

            if ($request->filled('item_id')) {
                $itemIds[] = $request->item_id;
            }

            if ($request->filled('item_ids')) {
                $ids = explode(',', $request->item_ids);
                $ids = array_map('trim', $ids);
                $ids = array_filter($ids, 'strlen');
                $itemIds = array_merge($itemIds, $ids);
            }

            if (empty($itemIds)) {
                return ResponseService::validationError(__('Please provide item_id or item_ids'));
            }

            $results = [];

            foreach ($itemIds as $id) {
                try {
                    $item = Item::owner()->with('gallery_images')->withTrashed()->findOrFail($id);

                    // Delete main image
                    FileService::delete($item->getRawOriginal('image'));

                    // Delete gallery images
                    if ($item->gallery_images->count() > 0) {
                        foreach ($item->gallery_images as $gallery) {
                            FileService::delete($gallery->getRawOriginal('image'));
                        }
                    }

                    // Delete item
                    $item->forceDelete();

                    $results[] = [
                        'status' => 'success',
                        'message' => __('Advertisement Deleted Successfully'),
                        'item_id' => $id,
                    ];
                } catch (Throwable $e) {
                    $results[] = [
                        'status' => 'failed',
                        'message' => __('Failed to delete item'),
                        'item_id' => $id,
                    ];
                }
            }

            // Single item response
            if (count($results) === 1) {
                if ($results[0]['status'] === 'success') {
                    return ResponseService::successResponse(
                        __('Advertisement Deleted Successfully'),
                        ['id' => $results[0]['item_id']]
                    );
                } else {
                    return ResponseService::errorResponse($results[0]['message']);
                }
            }

            // Multiple items response
            return ResponseService::successResponse(__('Items processed successfully'), $results);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> deleteItem');

            return ResponseService::errorResponse();
        }
    }

    public function updateItemStatus(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_id' => 'required|integer',
            'status' => 'required|in:sold out,inactive,active,resubmitted',
            // 'sold_to' => 'required_if:status,==,sold out|integer'
            'sold_to' => 'nullable|integer',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $item = Item::owner()->whereNotIn('status', ['review', 'permanent rejected'])->withTrashed()->findOrFail($request->item_id);
            if ($item->status == 'permanent rejected' && $request->status == 'resubmitted') {
                ResponseService::errorResponse(__('This Advertisement is permanently rejected and cannot be resubmitted'));
            }
            if ($request->status == 'inactive') {
                $item->delete();
            } elseif ($request->status == 'active') {
                $item->restore();
                $item->update(['status' => 'review']);
            } elseif ($request->status == 'sold out') {
                $item->update([
                    'status' => 'sold out',
                    'sold_to' => $request->sold_to,
                ]);
            } else {
                $item->update(['status' => $request->status]);
            }
            ResponseService::successResponse(__('Advertisement Status Updated Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'ItemController -> updateItemStatus');
            ResponseService::errorResponse(__('Something Went Wrong'));
        }
    }

    public function getItemBuyerList(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_id' => 'required|integer',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $buyer_ids = ItemOffer::where('item_id', $request->item_id)->select('buyer_id')->pluck('buyer_id');
            $users = User::select(['id', 'name', 'profile'])->whereIn('id', $buyer_ids)->get();
            ResponseService::successResponse(__('Buyer List fetched Successfully'), $users);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'ItemController -> updateItemStatus');
            ResponseService::errorResponse(__('Something Went Wrong'));
        }
    }

    public function getSubCategories(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'category_id' => 'nullable|integer',
            'listing' => 'nullable|in:0,1',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $subcategoryLimit = 15; // Limit subcategories per level for display

            // Get package category IDs for validation when category_id is passed with listing=1
            $packageCategoryIds = [];
            $hasGlobalPackage = false;
            $freeAdListing = Setting::where('name', 'free_ad_listing')->value('value') ?? 0;

            // Validate access when category_id is passed and listing=1
            if (! empty($request->category_id) && ! empty($request->listing) && $request->listing == 1 && $freeAdListing != 1 && Auth::check()) {
                // Get ALL active packages for the user (user can have multiple packages)
                $userPackages = UserPurchasedPackage::onlyActive()
                    ->whereHas('package', static function ($q) {
                        $q->where('type', 'item_listing');
                    })
                    ->where('user_id', Auth::id())
                    ->with('package.package_categories')
                    ->get();

                // Check if user has any global package
                foreach ($userPackages as $userPackage) {
                    if ($userPackage->package && $userPackage->package->is_global == 1) {
                        $hasGlobalPackage = true;
                        break;
                    }
                }

                // If no global package, collect category IDs from non-global packages
                if (! $hasGlobalPackage) {
                    foreach ($userPackages as $userPackage) {
                        if ($userPackage->package && $userPackage->package->is_global != 1 && $userPackage->package->package_categories) {
                            $packageCatIds = $userPackage->package->package_categories->pluck('category_id')->toArray();
                            $packageCategoryIds = array_merge($packageCategoryIds, $packageCatIds);
                        }
                    }
                    $packageCategoryIds = array_unique($packageCategoryIds);
                }
                // dd($packageCategoryIds);
                // Get the requested category
                $requestedCategory = Category::find($request->category_id);
                 $requestedCategory = Category::find($request->category_id);
                if ($requestedCategory) {
                    // Check if user has access to the category or any of its subcategories
                  if (! $hasGlobalPackage) {
                            $hasAccess = false;

                            // 1️⃣ Direct category access
                            if (in_array($requestedCategory->id, $packageCategoryIds)) {
                                $hasAccess = true;
                            }

                            // 2️⃣ Check ancestors (parent → root)
                            if (! $hasAccess) {
                                $ancestorIds = $requestedCategory->ancestors()
                                    ->where('status', 1)
                                    ->pluck('id')
                                    ->toArray();

                                if (! empty(array_intersect($ancestorIds, $packageCategoryIds))) {
                                    $hasAccess = true;
                                }
                            }

                            // 3️⃣ Check descendants (children → deep)
                            if (! $hasAccess) {
                                $descendantIds = $requestedCategory->descendants()
                                    ->where('status', 1)
                                    ->pluck('id')
                                    ->toArray();

                                if (! empty(array_intersect($descendantIds, $packageCategoryIds))) {
                                    $hasAccess = true;
                                }
                            }

                            // ❌ No access
                            if (! $hasAccess) {
                                ResponseService::errorResponse(
                                    __('You need to purchase a package for this category to access it.')
                                );
                            }
                        }

                    // If hasGlobalPackage is true, user has access to all categories
                } else {
                    ResponseService::errorResponse(__('Category not found.'));
                }
            }

            // Recursive function to load subcategories recursively
            $loadSubcategoriesRecursively = function ($query, $depth = 0, $maxDepth = 5) use (&$loadSubcategoriesRecursively) {
                if ($depth >= $maxDepth) {
                    return;
                }

                $query->where('status', 1)
                    ->orderBy('sequence', 'ASC')
                    ->with('translations')
                    ->withCount(['approved_items', 'subcategories' => function ($q) {
                        $q->where('status', 1);
                    }]);

                // Recursively load nested subcategories
                $query->with(['subcategories' => function ($subQuery) use (&$loadSubcategoriesRecursively, $depth, $maxDepth) {
                    $loadSubcategoriesRecursively($subQuery, $depth + 1, $maxDepth);
                }]);
            };

            // Helper to limit subcategories after loading (for performance - limits displayed subcategories)
            // Note: Item counts are calculated from ALL descendants, not just loaded ones
            $limitSubcategoriesAfterLoad = function ($categories, $limit, $depth = 0, $maxDepth = 5) use (&$limitSubcategoriesAfterLoad) {
                if ($depth >= $maxDepth || empty($categories)) {
                    return;
                }

                foreach ($categories as $category) {
                    if ($category->relationLoaded('subcategories') && $category->subcategories->isNotEmpty()) {
                        // Limit to first N subcategories for display
                        $limitedSubcategories = $category->subcategories->take($limit)->values();
                        $category->setRelation('subcategories', $limitedSubcategories);

                        // Recursively limit nested subcategories
                        $limitSubcategoriesAfterLoad($category->subcategories, $limit, $depth + 1, $maxDepth);
                    }
                }
            };

            $sql = Category::withCount(['subcategories' => function ($q) {
                $q->where('status', 1);
            }])->with('translations')->where(['status' => 1])->orderBy('sequence', 'ASC')
                ->with(['subcategories' => function ($query) use (&$loadSubcategoriesRecursively) {
                    $loadSubcategoriesRecursively($query, 0);
                }]);

            $parentCategory = null;

            // Return all categories regardless of listing parameter
            if (! empty($request->category_id)) {
                $sql = $sql->where('parent_category_id', $request->category_id);
                $parentCategory = Category::find($request->category_id);
            } elseif (! empty($request->slug)) {
                $parentCategory = Category::where('slug', $request->slug)->firstOrFail();
                $sql = $sql->where('parent_category_id', $parentCategory->id);
            } else {
                $sql = $sql->whereNull('parent_category_id');
            }

            $sql = $sql->paginate();

            // Limit subcategories to 15 per level (for performance)
            // Note: getAllItemsCountAttribute counts from ALL descendants, so count is accurate
            $limitSubcategoriesAfterLoad($sql->items(), $subcategoryLimit);

            // Calculate all_items_count for each category (includes ALL descendants, not just loaded ones)
            $sql->map(function ($category) {
                $category->all_items_count = $category->all_items_count;

                return $category;
            });

            ResponseService::successResponse(null, $sql, ['self_category' => $parentCategory ?? null]);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategories');
            ResponseService::errorResponse();
        }
    }

    public function getParentCategoryTree(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'child_category_id' => 'nullable|integer',
            'tree' => 'nullable|boolean',
            'slug' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $sql = Category::with('translations')->when($request->child_category_id, function ($sql) use ($request) {
                $sql->where('categories.id', $request->child_category_id);
            })
                ->when($request->slug, function ($sql) use ($request) {
                    $sql->where('slug', $request->slug);
                })
                ->firstOrFail()
                ->ancestorsAndSelf()->breadthFirst()->get();
            if ($request->tree) {
                $sql = $sql->toTree();
            }
            ResponseService::successResponse(null, $sql);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategories');
            ResponseService::errorResponse();
        }
    }

    public function getNotificationList(Request $request)
    {
        try {
            $user = Auth::user();
            $authId = $user->id;
            $userCreatedAt = $user->created_at; // Get user's registration date
            $id = $request->id;

            // 1. Build Base Query
            $query = Notifications::with(['item.area', 'item.translations'])
                ->where(function ($q) use ($authId, $userCreatedAt) {
                    // Specific notifications for this user
                    $q->whereRaw('FIND_IN_SET(?, user_id)', [$authId])
                        // Global notifications only if they were sent AFTER the user registered
                        ->orWhere(function ($sq) use ($userCreatedAt) {
                            $sq->where('send_to', 'all')
                                ->where('created_at', '>=', $userCreatedAt);
                        });
                });

            // 2. Filter by ID if passed, otherwise Paginate
            if (! empty($id)) {
                $notifications = $query->where('id', $id)->first();
                if (! $notifications) {
                    return ResponseService::successResponse(__('Notification not found'), null);
                }
                $notificationCollection = collect([$notifications]);
            } else {
                $notifications = $query->orderBy('id', 'DESC')->paginate();
                $notificationCollection = $notifications->getCollection();
            }

            $currentLanguage = app()->getLocale();
            $currentLangId = Language::where('code', $currentLanguage)->value('id');

            // 3. Process Logic
            foreach ($notificationCollection as $notification) {
                $item = $notification->item;
                if ($item) {
                    $city = City::with(['translations', 'state', 'country'])
                        ->where('name', $item->city)
                        ->whereHas('state', fn($q) => $q->where('name', $item->state))
                        ->first();

                    $translatedArea = $item->area->translated_name ?? '';
                    $translatedCity = $city?->translated_name ?? $item->city;
                    $translatedState = $city?->state?->translated_name ?? $item->state;
                    $translatedCountry = $city?->country?->translated_name ?? $item->country;

                    $item->translated_address = (! empty($translatedArea) ? $translatedArea . ', ' : '') .
                        $translatedCity . ', ' . $translatedState . ', ' . $translatedCountry;

                    if ($currentLanguage && $item->relationLoaded('translations')) {
                        $translation = $item->translations->firstWhere('language_id', $currentLangId);
                        if ($translation) {
                            $item->name = $translation->name;
                            $item->description = $translation->description;
                            $item->address = $translation->address;
                        }
                    }

                    $item->translated_area = $translatedArea;
                    $item->translated_city = $translatedCity;
                    $item->translated_state = $translatedState;
                    $item->translated_country = $translatedCountry;
                }
            }

            return ResponseService::successResponse(__('Notification fetched successfully'), $notifications);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getNotificationList');

            return ResponseService::errorResponse();
        }
    }

    public function getLanguages(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'language_code' => 'required',
                'type' => 'nullable|in:app,web',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }

            $language = Language::where('code', $request->language_code)->firstOrFail();

            // Determine requested file path
            $type = $request->type ?? 'app';
            $languageCode = $request->language_code;

            if ($type === 'web') {
                $json_file_path = base_path("resources/lang/{$language->web_file}");
                $default_file_path = base_path('resources/lang/en_web.json');
            } else {
                $json_file_path = base_path("resources/lang/{$language->app_file}");
                $default_file_path = base_path('resources/lang/en_app.json');
            }

            // If requested file doesn’t exist, fallback to default English file
            if (! is_file($json_file_path)) {
                if (is_file($default_file_path)) {
                    $json_file_path = $default_file_path;
                } else {
                    ResponseService::errorResponse(__('Default language file not found'));
                }
            }

            // Read file content safely
            $json_string = file_get_contents($json_file_path);

            try {
                $json_data = json_decode($json_string, false, 512, JSON_THROW_ON_ERROR);
            } catch (JsonException $e) {
                ResponseService::errorResponse(__('Invalid JSON format in the language file'));
            }

            $language->file_name = $json_data;

            ResponseService::successResponse(__('Data Fetched Successfully'), $language);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getLanguages');
            ResponseService::errorResponse();
        }
    }

    public function appPaymentStatus(Request $request)
    {
        try {
            $paypalInfo = $request->all();
            if (! empty($paypalInfo) && isset($_GET['st']) && strtolower($_GET['st']) == 'completed') {
                ResponseService::successResponse(__('Your Package will be activated within 10 Minutes'), $paypalInfo['txn_id']);
            } elseif (! empty($paypalInfo) && isset($_GET['st']) && strtolower($_GET['st']) == 'authorized') {
                ResponseService::successResponse(__('Your Transaction is Completed. Ads wil be credited to your account within 30 minutes.'), $paypalInfo);
            } else {
                ResponseService::errorResponse(__('Payment Cancelled / Declined'), (isset($_GET)) ? $paypalInfo : '');
            }
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> appPaymentStatus');
            ResponseService::errorResponse();
        }
    }

    public function getPaymentSettings()
    {
        try {
            $result = PaymentConfiguration::select(['currency_code', 'payment_method', 'api_key', 'status'])->where('status', 1)->get();
            $response = [];
            foreach ($result as $payment) {
                $response[$payment->payment_method] = $payment->toArray();
            }
            $settings = Setting::whereIn('name', [
                'account_holder_name',
                'bank_name',
                'account_number',
                'ifsc_swift_code',
                'bank_transfer_status',
            ])->get();

            $bankDetails = [];
            foreach ($settings as $row) {
                $key = ($row->name === 'bank_transfer_status') ? 'status' : $row->name;
                $bankDetails[$key] = $row->value;
            }
            $response['bankTransfer'] = $bankDetails;
            ResponseService::successResponse(__('Data Fetched Successfully'), $response);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getPaymentSettings');
            ResponseService::errorResponse();
        }
    }

    public function getCustomFields(Request $request)
    {
        try {

            $filter = filter_var($request->input('filter', false), FILTER_VALIDATE_BOOLEAN);
            $categoryIds = explode(',', $request->input('category_ids'));

            // Load custom fields
            $customFields = CustomField::with('translations')
                ->whereHas('custom_field_category', function ($q) use ($categoryIds) {
                    $q->whereIn('category_id', $categoryIds);
                })
                ->where('status', 1)
                ->get();

            // Apply filtering logic
            if ($filter === true) {

                // Modify the collection with filtering
                $customFields = $customFields->filter(function ($field) use ($categoryIds) {

                    // Only filter for dropdown/checkbox/radio
                    if (! in_array($field->type, ['dropdown', 'checkbox', 'radio'])) {
                        return true; // keep text, number etc.
                    }

                    // Get used values for this field (pluck only value column)
                    $values = ItemCustomFieldValue::where('custom_field_id', $field->id)
                        ->whereHas('item', function ($q) use ($categoryIds) {
                            $q->getNonExpiredItems()
                                ->whereNull('deleted_at')
                                ->where('status', 'approved')
                                ->whereIn('category_id', $categoryIds);
                        })
                        ->pluck('value')
                        ->toArray();

                    $used = [];

                    // Decode values properly
                    foreach ($values as $raw) {
                        $decoded = is_string($raw) ? json_decode($raw, true) : $raw;

                        if (is_array($decoded)) {
                            $used = array_merge($used, $decoded);
                        } else {
                            $used[] = $decoded;
                        }
                    }

                    $used = array_unique(array_filter($used));

                    // ❌ Remove the entire field if no used values exist
                    if (empty($used)) {
                        return false;
                    }

                    // Get original main language values before filtering
                    $originalMainValues = $field->values ?? [];

                    // Filter original field values
                    $field->values = array_values(array_intersect($originalMainValues, $used));

                    // Find indices of used values in original main language array
                    $usedIndices = [];
                    foreach ($field->values as $usedValue) {
                        $index = array_search($usedValue, $originalMainValues);
                        if ($index !== false) {
                            $usedIndices[] = $index;
                        }
                    }

                    // Filter translations by same indices to maintain alignment
                    foreach ($field->translations as $t) {
                        $translationValues = $t->value ?? [];
                        if (is_array($translationValues) && count($translationValues) > 0) {
                            $filteredTranslationValues = [];
                            foreach ($usedIndices as $idx) {
                                if (isset($translationValues[$idx])) {
                                    $filteredTranslationValues[] = $translationValues[$idx];
                                }
                            }
                            $t->value = array_values($filteredTranslationValues);
                        }
                    }

                    return true; // KEEP field
                })->values(); // re-index collection
            }

            // Load translated attributes
            $customFields->each(function ($field) {
                $field->translated_name = $field->translated_name;
                $field->translated_value = $field->translated_value;
            });

            ResponseService::successResponse(__('Data Fetched successfully'), $customFields);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCustomFields');
            ResponseService::errorResponse();
        }
    }

    public function makeFeaturedItem(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_id' => 'required|integer',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            DB::commit();
            $user = Auth::user();
            Item::where('status', 'approved')->findOrFail($request->item_id);
            $user_package = UserPurchasedPackage::onlyActive()
                ->where(['user_id' => $user->id])
                ->with('package')
                ->whereHas('package', function ($q) {
                    $q->where(['type' => 'advertisement']);
                })
                ->first();

            if (! $user_package) {
                return ResponseService::errorResponse(__('You need to purchase a Featured Ad plan first.'));
            }
            $featuredItems = FeaturedItems::where(['item_id' => $request->item_id, 'package_id' => $user_package->package_id])->first();
            if (! empty($featuredItems)) {
                ResponseService::errorResponse(__('Advertisement is already featured'));
            }

            $user_package->used_limit++;
            $user_package->save();

            FeaturedItems::create([
                'item_id' => $request->item_id,
                'package_id' => $user_package->package_id,
                'user_purchased_package_id' => $user_package->id,
                'start_date' => date('Y-m-d'),
                'end_date' => $user_package->end_date,
            ]);

            DB::commit();
            ResponseService::successResponse(__('Featured Advertisement Created Successfully'));
        } catch (Throwable $th) {
            DB::rollBack();
            ResponseService::logErrorResponse($th, 'API Controller -> createAdvertisement');
            ResponseService::errorResponse();
        }
    }

    public function manageFavourite(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'item_id' => 'required',
            ]);
            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            $favouriteItem = Favourite::where('user_id', Auth::user()->id)->where('item_id', $request->item_id)->first();
            if (empty($favouriteItem)) {
                $favouriteItem = new Favourite;
                $favouriteItem->user_id = Auth::user()->id;
                $favouriteItem->item_id = $request->item_id;
                $favouriteItem->save();
                ResponseService::successResponse(__('Advertisement added to Favourite'));
            } else {
                $favouriteItem->delete();
                ResponseService::successResponse(__('Advertisement remove from Favourite'));
            }
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> manageFavourite');
            ResponseService::errorResponse();
        }
    }

    public function getFavouriteItem(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'page' => 'nullable|integer',
                'limit' => 'nullable|integer',
            ]);
            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            $favouriteItemIDS = Favourite::where('user_id', Auth::user()->id)->select('item_id')->pluck('item_id');
            $items = Item::whereIn('id', $favouriteItemIDS)
                ->with('user:id,name,email,mobile,profile,country_code', 'category:id,name,image,is_job_category', 'gallery_images:id,image,item_id', 'featured_items', 'favourites', 'item_custom_field_values.custom_field')->where('status', 'approved')->onlyNonBlockedUsers()->getNonExpiredItems()->paginate();

            ResponseService::successResponse(__('Data Fetched Successfully'), new ItemCollection($items));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getFavouriteItem');
            ResponseService::errorResponse();
        }
    }

    public function getSlider(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'country' => 'nullable|string',
            'state' => 'nullable|string',
            'city' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {

            // Fetch IDs (single responsibility)
            $countryId = $request->country
                ? Country::where('name', $request->country)->value('id')
                : null;

            $stateId = $request->state
                ? State::where('name', $request->state)->value('id')
                : null;

            $cityId = $request->city
                ? City::where('name', $request->city)->value('id')
                : null;

            $rows = Slider::with([
                'model' => function (MorphTo $morphTo) {
                    $morphTo->constrain([
                        Category::class => fn($q) => $q->withCount('subcategories'),
                    ]);
                },
            ])->where(function ($query) {
                $query->whereNull('model_type')
                    ->orWhereHasMorph(
                        'model',
                        [Category::class, Item::class],
                        fn($q) => $q->whereNotNull('id')
                    );
            })
                ->where(function ($q) use ($countryId, $stateId, $cityId) {
                    if ($countryId || $stateId || $cityId) {
                        $q->where(function ($sub) use ($countryId, $stateId, $cityId) {
                            if ($countryId) {
                                $sub->orWhere('country_id', $countryId);
                            }
                            if ($stateId) {
                                $sub->orWhere('state_id', $stateId);
                            }
                            if ($cityId) {
                                $sub->orWhere('city_id', $cityId);
                            }
                        })
                            ->orWhere(function ($global) {
                                $global->whereNull('country_id')
                                    ->whereNull('state_id')
                                    ->whereNull('city_id');
                            });
                    } else {
                        $q->whereNull('country_id')
                            ->whereNull('state_id')
                            ->whereNull('city_id');
                    }
                })->get();

            ResponseService::successResponse(null, $rows);
        } catch (\Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getSlider');
            ResponseService::errorResponse();
        }
    }

    public function getReportReasons(Request $request)
    {
        try {
            $report_reason = new ReportReason;
            if (! empty($request->id)) {
                $id = $request->id;
                $report_reason->where('id', '=', $id);
            }
            $result = $report_reason->paginate();
            $total = $report_reason->count();
            ResponseService::successResponse(__('Data Fetched Successfully'), $result, ['total' => $total]);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getReportReasons');
            ResponseService::errorResponse();
        }
    }

    public function addReports(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'item_id' => 'required',
                'report_reason_id' => 'required_without:other_message',
                'other_message' => 'required_without:report_reason_id',
            ]);
            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            $user = Auth::user();
            $report_count = UserReports::where('item_id', $request->item_id)->where('user_id', $user->id)->first();
            if ($report_count) {
                ResponseService::errorResponse(__('Already Reported'));
            }
            UserReports::create([
                ...$request->all(),
                'user_id' => $user->id,
                'other_message' => $request->other_message ?? '',
            ]);
            ResponseService::successResponse(__('Report Submitted Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> addReports');
            ResponseService::errorResponse();
        }
    }

    public function setItemTotalClick(Request $request)
    {
        try {

            $validator = Validator::make($request->all(), [
                'item_id' => 'required',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            Item::findOrFail($request->item_id)->increment('clicks');
            ResponseService::successResponse(null, 'Update Successfully');
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> setItemTotalClick');
            ResponseService::errorResponse();
        }
    }

    public function getFeaturedSection(Request $request)
    {
        try {
            $featureSection = FeatureSection::with('translations')->orderBy('sequence', 'ASC');

            if (isset($request->slug)) {
                $featureSection->where('slug', $request->slug);
            }
            $featureSection = $featureSection->get();
            $tempRow = [];
            $rows = [];

            // Helper function to build base query
            // $buildBaseQuery = function () {
            //     return Item::where('status', 'approved')
            //         ->with('user:id,name,email,mobile,profile,is_verified,show_personal_details,country_code',
            //             'category:id,name,image,is_job_category,price_optional',
            //             'gallery_images:id,image,item_id',
            //             'featured_items',
            //             'favourites',
            //             'item_custom_field_values.custom_field.translations',
            //             'job_applications',
            //             'translations',
            //             'countryRelation:id,name',
            //             'countryRelation.translations:id,country_id,language_id,name',
            //             'countryRelation.currency:id,country_id,iso_code,symbol,symbol_position'
            //         )
            //         ->has('user')
            //         ->getNonExpiredItems();
            // };

            $buildBaseQuery = function () {
                return Item::query()
                    ->where('status', 'approved')
                    ->has('user')
                    ->with([
                        'user:id,name,mobile,profile,is_verified,show_personal_details,country_code',
                        'category:id,name,image,is_job_category,price_optional',
                        'gallery_images:id,image,item_id',
                        'featured_items',
                        'favourites',
                        'item_custom_field_values.custom_field.translations',
                        'job_applications',
                        'translations',
                        'countryRelation:id,name',
                        'countryRelation.translations:id,country_id,language_id,name',
                        'countryRelation.currency:id,country_id,iso_code,symbol,symbol_position',
                    ])
                    ->getNonExpiredItems();
            };

            // Helper function to apply auth filters
            $applyAuthFilters = function ($query) {
                if (Auth::check()) {
                    $query->with(['item_offers' => function ($q) {
                        $q->where('buyer_id', Auth::user()->id);
                    }, 'user_reports' => function ($q) {
                        $q->where('user_id', Auth::user()->id);
                    }]);
                }

                return $query;
            };

            $locationMessage = null;
            $baseItems = $buildBaseQuery();
            $locationResult = HelperService::applyLocationFilters($baseItems, $request, $applyAuthFilters);

            $filteredBaseQuery = clone $locationResult['query'];
            $sectionLocationMessage = $locationResult['message'];

            foreach ($featureSection as $row) {
                // Build base query with all eager loading
                // $baseItems = $buildBaseQuery();

                // Apply location filters using shared function
                // $locationResult = HelperService::applyLocationFilters($baseItems, $request, $applyAuthFilters);
                // $baseItems = $locationResult['query'];
                // $sectionLocationMessage = $locationResult['message'];
                $baseItems = clone $filteredBaseQuery;

                // Apply filter criteria
                $items = match ($row->filter) {
                    // 'price_criteria' => $baseItems->whereBetween('price', [$row->min_price, $row->max_price]),
                    'price_criteria' => $baseItems->where(function ($query) use ($row) {
                        $query->whereBetween('price', [$row->min_price, $row->max_price])
                            ->orWhere(function ($q) use ($row) {
                                $q->whereBetween('min_salary', [$row->min_price, $row->max_price])
                                    ->whereBetween('max_salary', [$row->min_price, $row->max_price]);
                            });
                    }),
                    'most_viewed' => $baseItems->orderBy('clicks', 'DESC'),
                    'category_criteria' => (static function () use ($row, $baseItems) {
                        $category = Category::whereIn('id', explode(',', $row->value))->with('children')->get();
                        $categoryIDS = HelperService::findAllCategoryIds($category);

                        return $baseItems->whereIn('category_id', $categoryIDS)->orderBy('id', 'DESC');
                    })(),
                    'most_liked' => $baseItems->withCount('favourites')->orderBy('favourites_count', 'DESC'),
                    'featured_ads' => $baseItems->has('featured_items')->orderBy('id', 'DESC'),
                };

                // Add auth-specific relationships
                if (Auth::check()) {
                    $items->with(['item_offers' => function ($q) {
                        $q->where('buyer_id', Auth::user()->id);
                    }, 'user_reports' => function ($q) {
                        $q->where('user_id', Auth::user()->id);
                    }]);
                }

                // Limit results early and get items
                $items = $items->limit(5)->get();

                // $items = $items->with('user:id,name,email,mobile,profile,is_verified,show_personal_details,country_code',
                //     'category:id,name,image,is_job_category,price_optional',
                //     'gallery_images:id,image,item_id',
                //     'featured_items',
                //     'favourites',
                //     'item_custom_field_values.custom_field.translations',
                //     'job_applications',
                //     'translations',
                //     'countryRelation:id,name',
                //     'countryRelation.translations:id,country_id,language_id,name',
                //     'countryRelation.currency:id,country_id,iso_code,symbol,symbol_position')->limit(5)->get();

                $tempRow[$row->id] = $row;
                $tempRow[$row->id]['total_data'] = count($items);
                if (count($items) > 0) {
                    $tempRow[$row->id]['section_data'] = new ItemCollection($items);
                } else {
                    $tempRow[$row->id]['section_data'] = [];
                }

                // Track location message for response (use first non-empty one)
                if (! empty($sectionLocationMessage) && empty($locationMessage)) {
                    $locationMessage = $sectionLocationMessage;
                }

                $rows[] = $tempRow[$row->id];
            }

            // Use location message if available, otherwise use default success message
            // dd([
            //     'queries' => \DB::getQueryLog(),
            //     'memory' => memory_get_peak_usage(true) / 1024 / 1024 .' MB',
            // ]);
            $responseMessage = ! empty($locationMessage) ? $locationMessage : __('Data Fetched Successfully');
            ResponseService::successResponse($responseMessage, $rows);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getFeaturedSection');
            ResponseService::errorResponse();
        }
    }

    public function getPaymentIntent(Request $request)
    {

        $validator = Validator::make($request->all(), [
            'package_id' => 'required',
            'payment_method' => 'required|in:Stripe,Razorpay,Paystack,PhonePe,FlutterWave,bankTransfer,PayPal',
            'platform_type' => 'required_if:payment_method,==,Paystack|string',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {

            DB::beginTransaction();

            if ($request->payment_method !== 'bankTransfer') {
                $paymentConfigurations = PaymentConfiguration::where(['status' => 1, 'payment_method' => $request->payment_method])->first();
                if (empty($paymentConfigurations)) {
                    ResponseService::errorResponse(__('Payment is not Enabled'));
                }
            } else {
                $bankTransferEnabled = Setting::where('name', 'bank_transfer_status')->value('value');
                if ($bankTransferEnabled != 1) {
                    ResponseService::errorResponse(__('Bank Transfer is not enabled.'));
                }
            }

            $package = Package::whereNot('final_price', 0)->findOrFail($request->package_id);

            $purchasedPackage = UserPurchasedPackage::onlyActive()->where(['user_id' => Auth::user()->id, 'package_id' => $request->package_id])->first();
            if (! empty($purchasedPackage)) {
                ResponseService::errorResponse(__('You already have purchased this package'));
            }
            if ($request->payment_method === 'bankTransfer') {
                $existingTransaction = PaymentTransaction::where('user_id', Auth::user()->id)
                    ->where('package_id', $request->package_id)
                    ->where('payment_gateway', $request->payment_method)
                    ->whereIn('payment_status', ['pending', 'under review'])
                    ->exists();

                $methodName = $paymentMethodNames[$request->payment_method] ?? ucfirst($request->payment_method);

                if ($existingTransaction) {
                    return ResponseService::errorResponse("A $methodName transaction for this package already exists.");
                }
            }
            $orderId = ($request->payment_method === 'bankTransfer') ? uniqid() . '-' . 'p' . '-' . $package->id : null;

            // Add Payment Data to Payment Transactions Table
            $paymentTransactionData = PaymentTransaction::create([
                'user_id' => Auth::user()->id,
                'package_id' => $request->package_id,
                'amount' => $package->final_price,
                'payment_gateway' => ucfirst($request->payment_method),
                'payment_status' => 'Pending',
                'order_id' => $orderId,
            ]);

            if ($request->payment_method === 'bankTransfer') {
                DB::commit();
                ResponseService::successResponse(__('Bank transfer initiated. Please complete the transfer and update the transaction.'), [
                    'payment_transaction_id' => $paymentTransactionData->id,
                    'payment_transaction' => $paymentTransactionData,
                ]);
            }

            $paymentIntent = PaymentService::create($request->payment_method)->createAndFormatPaymentIntent(round($package->final_price, 2), [
                'payment_transaction_id' => $paymentTransactionData->id,
                'package_id' => $package->id,
                'user_id' => Auth::user()->id,
                'email' => Auth::user()->email,
                'platform_type' => $request->platform_type,
            ]);
            $paymentTransactionData->update(['order_id' => $paymentIntent['id']]);

            $paymentTransactionData = PaymentTransaction::findOrFail($paymentTransactionData->id);
            // Custom Array to Show as response
            $paymentGatewayDetails = [
                ...$paymentIntent,
                'payment_transaction_id' => $paymentTransactionData->id,
            ];

            DB::commit();
            ResponseService::successResponse('', ['payment_intent' => $paymentGatewayDetails, 'payment_transaction' => $paymentTransactionData]);
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function getPaymentTransactions(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'latest_only' => 'nullable|boolean',
            'page' => 'nullable',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $paymentTransactions = PaymentTransaction::where('user_id', Auth::user()->id)->orderBy('id', 'DESC');
            if ($request->latest_only) {
                $paymentTransactions->where('created_at', '>', Carbon::now()->subMinutes(30)->toDateTimeString());
            }
            $paymentTransactions = $paymentTransactions->paginate();

            $formatter = app(CurrencyFormatterService::class);

            $paymentTransactions->getCollection()->transform(function ($data) use ($formatter) {
                if ($data->payment_status == 'pending') {
                    try {
                        $paymentIntent = PaymentService::create($data->payment_gateway)->retrievePaymentIntent($data->order_id);
                        // dd($paymentIntent);
                    } catch (Throwable) {
                        //                        PaymentTransaction::find($data->id)->update(['payment_status' => "failed"]);
                    }

                    if (! empty($paymentIntent) && $paymentIntent['status'] != 'pending') {
                        PaymentTransaction::find($data->id)->update(['payment_status' => $paymentIntent['status'] ?? 'failed']);
                    }
                }
                $data->formatted_amount = $formatter->formatPrice($data->amount);
                $data->payment_reciept = $data->payment_reciept;

                return $data;
            });

            ResponseService::successResponse(__('Payment Transactions Fetched'), $paymentTransactions);
        } catch (Throwable $e) {
            ResponseService::logErrorResponse($e);
            ResponseService::errorResponse();
        }
    }

    public function createItemOffer(Request $request)
    {

        $validator = Validator::make($request->all(), [
            'item_id' => 'required|integer',
            'amount' => 'nullable|numeric',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $item = Item::approved()->notOwner()->findOrFail($request->item_id);
            $itemOffer = ItemOffer::updateOrCreate([
                'item_id' => $request->item_id,
                'buyer_id' => Auth::user()->id,
                'seller_id' => $item->user_id,
            ], ['amount' => $request->amount]);

            $itemOffer = $itemOffer->load('seller:id,name,profile', 'buyer:id,name,profile', 'item:id,name,description,price,image');

            $fcmMsg = [
                'user_id' => $itemOffer->buyer->id,
                'user_name' => $itemOffer->buyer->name,
                'user_profile' => $itemOffer->buyer->profile,
                'user_type' => 'Buyer',
                'item_id' => $itemOffer->item->id,
                'item_name' => $itemOffer->item->name,
                'item_image' => $itemOffer->item->image,
                'item_price' => $itemOffer->item->price,
                'item_offer_id' => $itemOffer->id,
                'item_offer_amount' => $itemOffer->amount,
                // 'type'              => $notificationPayload['message_type'],
                // 'message_type_temp' => $notificationPayload['message_type']
            ];
            /* message_type is reserved keyword in FCM so removed here */
            unset($fcmMsg['message_type']);
            if ($request->has('amount') && $request->amount != 0) {
                $user_token = UserFcmToken::where('user_id', $item->user->id)->pluck('fcm_token')->toArray();
                $message = 'new offer is created by buyer';
                NotificationService::sendFcmNotification($user_token, 'New Offer', $message, 'offer', $fcmMsg);
            }

            ResponseService::successResponse(__('Advertisement Offer Created Successfully'), $itemOffer);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> createItemOffer');
            ResponseService::errorResponse();
        }
    }

    public function getChatList(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'type' => 'required|in:seller,buyer',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }

        try {
            $authId = Auth::user()->id;

            // 1. Get Blocked Users Lists
            $authUserBlockList = BlockUser::where('user_id', $authId)->pluck('blocked_user_id');
            $otherUserBlockList = BlockUser::where('blocked_user_id', $authId)->pluck('user_id');

            // 2. Prepare the Base Query
            $query = ItemOffer::with([
                'seller:id,name,profile',
                'buyer:id,name,profile',
                'item' => function ($q) {
                    $q->with(['currency:id,iso_code,symbol,symbol_position', 'category:id,name,image,is_job_category,price_optional']);
                },
                'chat' => function ($q) {
                    $q->latest('updated_at')->select('updated_at', 'item_offer_id', 'is_read', 'sender_id');
                },
                'item.review' => function ($q) use ($authId) {
                    $q->where('buyer_id', $authId);
                }
            ])
                ->whereHas('buyer', function ($query) {
                    $query->whereNull('deleted_at');
                })
                ->withCount([
                    'chat as unread_chat_count' => function ($query) use ($authId) {
                        $query->where('is_read', 0)
                            ->where('sender_id', '!=', $authId);
                    },
                ]);

            // Filter by type
            if ($request->type == 'seller') {
                $query->where('seller_id', $authId);
            } else {
                $query->where('buyer_id', $authId);
            }

            // 3. CALCULATE GLOBAL UNREAD COUNT (For all pages)
            // We clone the query to get the total sum without pagination limits
            $totalUnreadChatCount = (int) (clone $query)->get()->sum('unread_chat_count');

            // 4. APPLY STABLE ORDERING AND PAGINATE
            $itemOffer = $query->orderByDesc('unread_chat_count')
                ->orderByDesc(function ($q) {
                    $q->select('updated_at')
                        ->from('chats')
                        ->whereColumn('item_offer_id', 'item_offers.id')
                        ->orderByDesc('updated_at')
                        ->limit(1);
                })
                ->orderBy('id', 'DESC') // Tie-breaker ensures Page 1 items don't show on Page 2
                ->paginate();

            // 5. DATA FORMATTING (Single Transform)
            $formatter = app(currencyFormatterService::class);

            $itemOffer->getCollection()->transform(function ($offer) use ($request, $authId, $authUserBlockList, $otherUserBlockList, $formatter) {

                // Block logic
                if ($request->type === 'seller') {
                    $userBlocked = $authUserBlockList->contains($offer->buyer_id) || $otherUserBlockList->contains($offer->seller_id);
                } else {
                    $userBlocked = $authUserBlockList->contains($offer->seller_id) || $otherUserBlockList->contains($offer->buyer_id);
                }
                $offer->user_blocked = $userBlocked;

                // Chat timing logic
                $latestChat = $offer->chat->first();
                $offer->last_message_time = $latestChat ? $latestChat->updated_at : $offer->updated_at;

                // Item and Currency Formatting
                if ($offer->item) {
                    $item = $offer->item;
                    $item->is_purchased = ($item->sold_to == $authId) ? 1 : 0;

                    // Handle Review Relation (Convert collection to single object)
                    $item->setRelation('review', optional($item->review)->first());
                    $currency = $item?->currency ?? null;
                    $item->formatted_price = $formatter->formatPrice($item->price, $currency);
                    $item->formatted_min_salary = $formatter->formatPrice($item->min_salary, $currency);
                    $item->formatted_max_salary = $formatter->formatPrice($item->max_salary, $currency);
                    $item->formatted_salary_range = $formatter->formatSalaryRange($item->min_salary, $item->max_salary, $currency);
                }

                // Offer amount formatting
                $offerCurrency = $offer->item ? ($offer->item->currency ?? null) : null;
                $offer->formatted_amount = $formatter->formatPrice($offer->amount, $offerCurrency);

                return $offer;
            });

            return ResponseService::successResponse(
                __('Chat List Fetched Successfully'),
                $itemOffer,
                ['total_unread_chat_count' => $totalUnreadChatCount]
            );
        } catch (\Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getChatList');

            return ResponseService::errorResponse('Something went wrong');
        }
    }

    public function sendMessage(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_offer_id' => 'required|integer',
            'message' => (! $request->file('file') && ! $request->file('audio')) ? 'required' : 'nullable',
            'file' => 'nullable|mimes:jpg,jpeg,png|max:7168',
            'audio' => 'nullable|mimetypes:audio/mpeg,video/webm,audio/ogg,video/mp4,audio/x-wav,text/plain|max:7168',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            DB::beginTransaction();
            $user = Auth::user();
            // List of users that Auth user has blocked
            $authUserBlockList = BlockUser::where('user_id', $user->id)->get();

            // List of Other users that have blocked the Auth user
            $otherUserBlockList = BlockUser::where('blocked_user_id', $user->id)->get();

            $itemOffer = ItemOffer::with('item')->findOrFail($request->item_offer_id);
            if ($itemOffer->seller_id == $user->id) {
                // If Auth user is seller then check if buyer has blocked the user
                $blockStatus = $authUserBlockList->filter(function ($data) use ($itemOffer) {
                    return $data->user_id == $itemOffer->seller_id && $data->blocked_user_id == $itemOffer->buyer_id;
                });
                if (count($blockStatus) !== 0) {
                    ResponseService::errorResponse(__('You Cannot send message because You have blocked this user'));
                }

                $blockStatus = $otherUserBlockList->filter(function ($data) use ($itemOffer) {
                    return $data->user_id == $itemOffer->buyer_id && $data->blocked_user_id == $itemOffer->seller_id;
                });
                if (count($blockStatus) !== 0) {
                    ResponseService::errorResponse(__('You Cannot send message because other user has blocked you.'));
                }
            } else {
                // If Auth user is seller then check if buyer has blocked the user
                $blockStatus = $authUserBlockList->filter(function ($data) use ($itemOffer) {
                    return $data->user_id == $itemOffer->buyer_id && $data->blocked_user_id == $itemOffer->seller_id;
                });
                if (count($blockStatus) !== 0) {
                    ResponseService::errorResponse(__('You Cannot send message because You have blocked this user'));
                }

                $blockStatus = $otherUserBlockList->filter(function ($data) use ($itemOffer) {
                    return $data->user_id == $itemOffer->seller_id && $data->blocked_user_id == $itemOffer->buyer_id;
                });
                if (count($blockStatus) !== 0) {
                    ResponseService::errorResponse(__('You Cannot send message because other user has blocked you.'));
                }
            }
            $chat = Chat::create([
                'sender_id' => Auth::user()->id,
                'item_offer_id' => $request->item_offer_id,
                'message' => $request->message,
                'file' => $request->hasFile('file') ? FileService::compressAndUpload($request->file('file'), 'chat') : '',
                'audio' => $request->hasFile('audio') ? FileService::compressAndUpload($request->file('audio'), 'chat') : '',
                'is_read' => 0,
            ]);

            if ($itemOffer->seller_id == $user->id) {
                $receiver_id = $itemOffer->buyer_id;
                $userType = 'Seller';
            } else {
                $receiver_id = $itemOffer->seller_id;
                $userType = 'Buyer';
            }
            $notificationPayload = $chat->toArray();

            $unreadMessagesCount = Chat::where('item_offer_id', $itemOffer->id)
                ->where('is_read', 0)
                ->count();

            $fcmMsg = [
                ...$notificationPayload,
                'user_id' => $user->id,
                'user_name' => $user->name,
                'user_profile' => $user->profile,
                'user_type' => $userType,
                'item_id' => $itemOffer->item->id,
                'item_name' => $itemOffer->item->name,
                'item_image' => $itemOffer->item->image,
                'item_price' => $itemOffer->item->price,
                'item_offer_id' => $itemOffer->id,
                'item_offer_amount' => $itemOffer->amount,
                'type' => $notificationPayload['message_type'],
                'message_type_temp' => $notificationPayload['message_type'],
                'unread_count' => $unreadMessagesCount,
            ];
            /* message_type is reserved keyword in FCM so removed here */
            unset($fcmMsg['message_type']);
            $displayMessage = $request->message;
            if (empty($displayMessage)) {
                if ($request->hasFile('file')) {
                    $mime = $request->file('file')->getMimeType();

                    if (str_contains($mime, 'image')) {
                        $displayMessage = '📷 Sent you an image';
                    } elseif (str_contains($mime, 'pdf')) {
                        $displayMessage = '📄 Sent you a PDF file';
                    } elseif (str_contains($mime, 'word')) {
                        $displayMessage = '📘 Sent you a document';
                    } elseif (str_contains($mime, 'text')) {
                        $displayMessage = '📄 Sent you a text file';
                    } else {
                        $displayMessage = '📎 Sent you a file';
                    }
                } elseif ($request->hasFile('audio')) {
                    $displayMessage = '🎤 Sent you an audio message';
                } else {
                    $displayMessage = '💬 Sent you a message';
                }
            }

            $receiverFCMTokens = UserFcmToken::where('user_id', $receiver_id)->pluck('fcm_token')->toArray();
            DB::commit();

            $notification = NotificationService::sendFcmNotification($receiverFCMTokens, 'Message', $displayMessage, 'chat', $fcmMsg);

            ResponseService::successResponse(__('Message Fetched Successfully'), $chat, ['debug' => $notification]);
        } catch (Throwable $th) {
            DB::rollBack();
            ResponseService::logErrorResponse($th, 'API Controller -> sendMessage');
            ResponseService::errorResponse();
        }
    }

    public function getChatMessages(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_offer_id' => 'required',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $itemOffer = ItemOffer::owner()->findOrFail($request->item_offer_id);
            $chat = Chat::where('item_offer_id', $itemOffer->id)->orderBy('created_at', 'DESC')->paginate();
            $authUserId = auth::user()->id;
            Chat::where('item_offer_id', $itemOffer->id)
                ->where('sender_id', '!=', $authUserId)
                ->whereIn('id', $chat->pluck('id'))
                ->update(['is_read' => '1']);
            ResponseService::successResponse(__('Messages Fetched Successfully'), $chat);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getChatMessages');
            ResponseService::errorResponse();
        }
    }

    public function deleteUser()
    {
        try {
            User::findOrFail(Auth::user()->id)->forceDelete();
            ResponseService::successResponse(__('User Deleted Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> deleteUser');
            ResponseService::errorResponse();
        }
    }

    public function inAppPurchase(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'purchase_token' => 'required',
            'payment_method' => 'required|in:google,apple',
            'package_id' => 'required|integer',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {
            $package = Package::findOrFail($request->package_id);
            $purchasedPackage = UserPurchasedPackage::where(['user_id' => Auth::user()->id, 'package_id' => $request->package_id])->first();
            if (! empty($purchasedPackage)) {
                ResponseService::errorResponse(__('You already have purchased this package'));
            }

            PaymentTransaction::create([
                'user_id' => Auth::user()->id,
                'amount' => $package->final_price,
                'payment_gateway' => $request->payment_method,
                'order_id' => $request->purchase_token,
                'payment_status' => 'success',
            ]);

            UserPurchasedPackage::create([
                'user_id' => Auth::user()->id,
                'package_id' => $request->package_id,
                'start_date' => Carbon::now(),
                'total_limit' => $package->item_limit == 'unlimited' ? null : $package->item_limit,
                'end_date' => $package->duration == 'unlimited' ? null : Carbon::now()->addDays($package->duration),
            ]);
            ResponseService::successResponse(__('Package Purchased Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> inAppPurchase');
            ResponseService::errorResponse();
        }
    }

    public function blockUser(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'blocked_user_id' => 'required|integer',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            BlockUser::create([
                'user_id' => Auth::user()->id,
                'blocked_user_id' => $request->blocked_user_id,
            ]);
            ResponseService::successResponse(__('User Blocked Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> blockUser');
            ResponseService::errorResponse();
        }
    }

    public function unblockUser(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'blocked_user_id' => 'required|integer',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            BlockUser::where([
                'user_id' => Auth::user()->id,
                'blocked_user_id' => $request->blocked_user_id,
            ])->delete();
            ResponseService::successResponse(__('User Unblocked Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> unblockUser');
            ResponseService::errorResponse();
        }
    }

    public function getBlockedUsers()
    {
        try {
            $blockedUsers = BlockUser::where('user_id', Auth::user()->id)->pluck('blocked_user_id');
            $users = User::whereIn('id', $blockedUsers)->select(['id', 'name', 'profile'])->get();
            ResponseService::successResponse(__('User Unblocked Successfully'), $users);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> unblockUser');
            ResponseService::errorResponse();
        }
    }

    public function getTips()
    {
        try {
            $tips = Tip::select(['id', 'description'])->orderBy('sequence', 'ASC')->with('translations')->get();
            ResponseService::successResponse(__('Tips Fetched Successfully'), $tips);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getTips');
            ResponseService::errorResponse();
        }
    }

    public function getBlog(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'category_id' => 'nullable|integer|exists:categories,id',
                'blog_id' => 'nullable|integer|exists:blogs,id',
                'sort_by' => 'nullable|in:new-to-old,old-to-new,popular',
                'views' => 'nullable|boolean',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }

            if ($request->views == 1) {
                if (! empty($request->id)) {
                    Blog::where('blogs.id', $request->id)->increment('views');
                } elseif (! empty($request->slug)) {
                    Blog::where('slug', $request->slug)->increment('views');
                } else {
                    return ResponseService::errorResponse(__('ID or Slug is required to increment views'));
                }
            }
            $blogs = Blog::with('translations')->when(! empty($request->id), static function ($q) use ($request) {
                $q->where('blogs.id', $request->id);
                Blog::where('blogs.id', $request->id);
            })
                ->when(! empty($request->slug), function ($q) use ($request) {
                    $q->where('slug', $request->slug);
                    Blog::where('slug', $request->slug);
                })
                ->when(! empty($request->sort_by), function ($q) use ($request) {
                    if ($request->sort_by === 'new-to-old') {
                        $q->orderByDesc('created_at');
                    } elseif ($request->sort_by === 'old-to-new') {
                        $q->orderBy('created_at');
                    } elseif ($request->sort_by === 'popular') {
                        $q->orderByDesc('views');
                    }
                })
                ->when(! empty($request->tag), function ($q) use ($request) {
                    $q->where(function ($query) use ($request) {
                        $query->where('tags', 'like', '%' . $request->tag . '%')
                            ->orWhereHas('translations', function ($translationQuery) use ($request) {
                                $translationQuery->where('tags', 'like', '%' . $request->tag . '%');
                            });
                    });
                })
                ->paginate();

            $otherBlogs = [];
            if (! empty($request->id) || ! empty($request->slug)) {
                $otherBlogs = Blog::with('translations')
                    ->when(! empty($request->id), function ($q) use ($request) {
                        $q->where('blogs.id', '!=', $request->id);
                    })
                    ->when(! empty($request->slug), function ($q) use ($request) {
                        $q->where('slug', '!=', $request->slug);
                    })
                    ->orderByDesc('id')
                    ->limit(3)
                    ->get();
            }

            ResponseService::successResponse(__('Blogs fetched successfully'), $blogs, ['other_blogs' => $otherBlogs]);
        } catch (Throwable $th) {
            // Log and handle exceptions
            ResponseService::logErrorResponse($th, 'API Controller -> getBlog');
            ResponseService::errorResponse(__('Failed to fetch blogs'));
        }
    }

    public function getCountries(Request $request)
    {
        try {
            $searchQuery = $request->search ?? '';
            $countries = Country::withCount('states')
                ->where(function ($query) use ($searchQuery) {
                    $query->where('name', 'LIKE', "%{$searchQuery}%")
                        ->orWhereHas('nameTranslations', function ($q) use ($searchQuery) {
                            $q->where('name', 'LIKE', "%{$searchQuery}%");
                        });
                })
                ->with(['nameTranslations.language:id,code'])
                ->orderBy('name', 'ASC')
                ->paginate();

            // Map translations to include `language_code`
            $countries->getCollection()->transform(function ($country) {
                if ($country->translations instanceof \Illuminate\Support\Collection) {
                    $country->translations = $country->translations->map(function ($translation) {
                        return [
                            'id' => $translation->id,
                            'country_id' => $translation->country_id,
                            'language_id' => $translation->language_id,
                            'name' => $translation->name,
                            'language_code' => optional($translation->language)->code,
                        ];
                    });
                } else {
                    // if somehow it's not a collection, fallback
                    $country->translations = [];
                }

                return $country;
            });

            ResponseService::successResponse(__('Countries Fetched Successfully'), $countries);
        } catch (Throwable $th) {
            // Log and handle any exceptions
            ResponseService::logErrorResponse($th, 'API Controller -> getCountries');
            ResponseService::errorResponse(__('Failed to fetch countries'));
        }
    }

    public function getStates(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'country_id' => 'nullable|integer',
            'search' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        try {
            $searchQuery = $request->search ?? '';
            $statesQuery = State::withCount('cities')
                ->where('name', 'LIKE', "%{$searchQuery}%")
                ->orderBy('name', 'ASC');

            if (isset($request->country_id)) {
                $statesQuery->where('country_id', $request->country_id);
            }

            $states = $statesQuery->paginate();

            ResponseService::successResponse(__('States Fetched Successfully'), $states);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller->getStates');
            ResponseService::errorResponse(__('Failed to fetch states'));
        }
    }

    public function getCities(Request $request)
    {
        try {
            // Validate
            $validator = Validator::make($request->all(), [
                'state_id' => 'nullable|integer',
                'search' => 'nullable|string',
            ]);

            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }

            $searchQuery = $request->search ?? '';

            // Base query
            $citiesQuery = City::with('translations')
                ->withCount('areas')
                ->orderBy('cities.name', 'ASC'); // force main table for sorting

            // Search filter: main name OR translated name
            if ($searchQuery !== '') {
                $citiesQuery->where(function ($q) use ($searchQuery) {
                    $q->where('cities.name', 'LIKE', "%{$searchQuery}%")
                        ->orWhereHas('translations', function ($t) use ($searchQuery) {
                            $t->where('name', 'LIKE', "%{$searchQuery}%");
                        });
                });
            }

            // State filter
            if ($request->filled('state_id')) {
                $citiesQuery->where('cities.state_id', $request->state_id);
            }

            // Pagination
            $cities = $citiesQuery->paginate();

            return ResponseService::successResponse(__('Cities Fetched Successfully'), $cities);
        } catch (\Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller->getCities');

            return ResponseService::errorResponse(__('Failed to fetch cities'));
        }
    }

    public function getAreas(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'city_id' => 'nullable|integer',
            'search' => 'nullable',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $searchQuery = $request->search ?? '';
            $data = Area::with('translations')->search($searchQuery)->orderBy('name', 'ASC');
            if (isset($request->city_id)) {
                $data->where('city_id', $request->city_id);
            }

            $data = $data->paginate();
            ResponseService::successResponse(__('Area fetched Successfully'), $data);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getAreas');
            ResponseService::errorResponse();
        }
    }

    public function getFaqs()
    {
        try {
            $faqs = Faq::with('translations')->get();
            ResponseService::successResponse(__('FAQ Data fetched Successfully'), $faqs);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getFaqs');
            ResponseService::errorResponse(__('Failed to fetch Faqs'));
        }
    }

    public function getAllBlogTags()
    {
        try {
            $languageCode = request()->header('Content-Language') ?? app()->getLocale();

            $language = Language::select(['id', 'code', 'name'])
                ->where('code', $languageCode)
                ->first();

            if (! $language) {
                return ResponseService::errorResponse('Invalid language code');
            }

            $tagsMap = [];

            Blog::with(['translations' => function ($q) use ($language) {
                $q->where('language_id', $language->id);
            }])->chunk(100, function ($blogs) use (&$tagsMap) {
                foreach ($blogs as $blog) {
                    $defaultTagsRaw = $blog->tags;
                    $defaultTags = [];
                    if (! empty($defaultTagsRaw)) {
                        if (is_string($defaultTagsRaw)) {
                            $decoded = json_decode($defaultTagsRaw, true);
                            if (json_last_error() === JSON_ERROR_NONE && ! empty($decoded)) {
                                $defaultTags = is_array($decoded) ? $decoded : [$decoded];
                            } else {
                                $defaultTags = array_map('trim', explode(',', $defaultTagsRaw));
                            }
                        } elseif (is_array($defaultTagsRaw)) {
                            $defaultTags = $defaultTagsRaw;
                        }
                    }
                    $translatedTagsRaw = $blog->translations->first()?->tags;
                    $translatedTags = [];
                    if (! empty($translatedTagsRaw)) {
                        if (is_string($translatedTagsRaw)) {
                            $decoded = json_decode($translatedTagsRaw, true);
                            if (json_last_error() === JSON_ERROR_NONE && ! empty($decoded)) {
                                $translatedTags = is_array($decoded) ? $decoded : [$decoded];
                            } else {
                                $translatedTags = array_map('trim', explode(',', $translatedTagsRaw));
                            }
                        } elseif (is_array($translatedTagsRaw)) {
                            $translatedTags = $translatedTagsRaw;
                        }
                    }
                    foreach ($defaultTags as $index => $defaultTag) {
                        $translated = $translatedTags[$index] ?? $defaultTag;
                        $tagsMap[$defaultTag] = $translated;
                    }
                }
            });
            $result = [];
            foreach ($tagsMap as $defaultTag => $translatedTag) {
                $result[] = [
                    'label' => $translatedTag,
                    'value' => $defaultTag,
                ];
            }

            ResponseService::successResponse('Blog Tags Retrieved Successfully', array_values($result));
        } catch (\Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getAllBlogTags');

            return ResponseService::errorResponse('Failed to fetch Tags');
        }
    }

    public function storeContactUs(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'email' => 'required|email',
            'subject' => 'required',
            'message' => 'required',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            ContactUs::create($request->all());
            ResponseService::successResponse(__('Contact Us Stored Successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> storeContactUs');
            ResponseService::errorResponse();
        }
    }

    public function addItemReview(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'review' => 'nullable|string',
            'ratings' => 'required|numeric|between:0,5',
            'item_id' => 'required',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $item = Item::with('user')->notOwner()->findOrFail($request->item_id);
            if ($item->sold_to !== Auth::id()) {
                ResponseService::errorResponse(__('You can only review items that you have purchased.'));
            }
            if ($item->status !== 'sold out') {
                ResponseService::errorResponse(__("The item must be marked as 'sold out' before you can review it."));
            }
            $existingReview = SellerRating::where('item_id', $request->item_id)->where('buyer_id', Auth::id())->first();
            if ($existingReview) {
                ResponseService::errorResponse(__('You have already reviewed this item.'));
            }
            $review = SellerRating::create([
                'item_id' => $request->item_id,
                'buyer_id' => Auth::user()->id,
                'seller_id' => $item->user_id,
                'ratings' => $request->ratings,
                'review' => $request->review ?? '',
            ]);
            $user_token = UserFcmToken::where('user_id', $item->user_id)->pluck('fcm_token')->toArray();
            if (! empty($user_token)) {
                NotificationService::sendFcmNotification(
                    $user_token,
                    'New Review',
                    'A new review has been added to your advertisement: ' . $item->name,
                    'item-review',
                    ['item_id' => $item->id]
                );
            }

            ResponseService::successResponse(__('Your review has been submitted successfully.'), $review);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> storeContactUs');
            ResponseService::errorResponse();
        }
    }

    public function getSeller(Request $request)
    {
        $request->validate([
            'id' => 'required|integer',
        ]);

        try {
            // Fetch seller by ID
            $seller = User::findOrFail($request->id);

            // Fetch seller ratings
            $ratings = SellerRating::where('seller_id', $seller->id)->with('buyer:id,name,profile')->paginate(10);
            $averageRating = $ratings->avg('ratings');

            // Response structure
            $response = [
                'seller' => [
                    ...$seller->toArray(),
                    'average_rating' => $averageRating,
                ],
                'ratings' => $ratings,
            ];

            // Send success response
            ResponseService::successResponse(__('Seller Details Fetched Successfully'), $response);
        } catch (Throwable $th) {
            // Log and handle error response
            ResponseService::logErrorResponse($th, 'API Controller -> getSeller');
            ResponseService::errorResponse();
        }
    }

    public function renewItem(Request $request)
    {
        try {
            $free_ad_listing = Setting::where('name', 'free_ad_listing')->value('value') ?? 0;

            // Validation rules
            $rules = [
                'item_id' => 'nullable|exists:items,id',
                'item_ids' => 'nullable|string', // accept comma-separated string
            ];

            if ($free_ad_listing == 0) {
                $rules['package_id'] = 'required|exists:packages,id';
            } else {
                $rules['package_id'] = 'nullable|exists:packages,id';
            }

            $validator = Validator::make($request->all(), $rules);

            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }

            // Normalize input to array
            $itemIds = [];

            if ($request->filled('item_id')) {
                $itemIds[] = $request->item_id;
            }

            if ($request->filled('item_ids')) {
                // Convert comma-separated string into array
                $ids = explode(',', $request->item_ids);
                $ids = array_map('trim', $ids);       // remove spaces
                $ids = array_filter($ids, 'strlen');  // remove empty values
                $itemIds = array_merge($itemIds, $ids);
            }

            if (empty($itemIds)) {
                return ResponseService::validationError(__('Please provide item_id or item_ids'));
            }

            $user = Auth::user();
            $package = null;
            $userPackage = null;

            // Fetch package if provided
            if ($request->filled('package_id')) {
                $package = Package::where('id', $request->package_id)->firstOrFail();

                $userPackage = UserPurchasedPackage::onlyActive()
                    ->where([
                        'user_id' => $user->id,
                        'package_id' => $package->id,
                    ])->first();

                if (! $userPackage) {
                    return ResponseService::errorResponse(__('You have not purchased this package'));
                }
            }

            $currentDate = Carbon::now();
            $results = [];

            foreach ($itemIds as $itemId) {
                $item = Item::findOrFail($itemId);
                $rawStatus = $item->getAttributes()['status'];

                if (Carbon::parse($item->expiry_date)->gt($currentDate)) {
                    $results[$itemId] = [
                        'status' => 'failed',
                        'message' => __('Advertisement has not expired yet, so it cannot be renewed'),
                    ];

                    continue;
                }
                if ($package) {
                    // Calculate expiry date based on package listing duration
                    $expiryDate = HelperService::calculateItemExpiryDate($package, $userPackage);
                    $item->expiry_date = $expiryDate;

                    $userPackage->used_limit++;
                    $userPackage->save();
                } else {
                    // No package - use standard 30 days
                    $item->expiry_date = $currentDate->copy()->addDays(30);
                }

                $item->status = $rawStatus;
                $item->save();

                $results[$itemId] = [
                    'status' => 'success',
                    'item' => $item,
                ];
            }

            // Return single item response if only one item was renewed
            if (count($itemIds) === 1) {
                $itemId = $itemIds[0];
                if ($results[$itemId]['status'] === 'success') {
                    return ResponseService::successResponse(
                        __('Advertisement renewed successfully'),
                        $results[$itemId]['item']
                    );
                } else {
                    return ResponseService::errorResponse($results[$itemId]['message']);
                }
            }

            // Return multiple items response
            return ResponseService::successResponse(__('Items processed successfully'), $results);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> renewItem');

            return ResponseService::errorResponse();
        }
    }

    public function getMyReview(Request $request)
    {
        try {
            $ratings = SellerRating::where('seller_id', Auth::user()->id)->with('seller:id,name,profile', 'buyer:id,name,profile', 'item:id,name,price,image,description')->paginate(10);
            $averageRating = $ratings->avg('ratings');
            $response = [
                'average_rating' => $averageRating,
                'ratings' => $ratings,
            ];

            ResponseService::successResponse(__('Seller Details Fetched Successfully'), $response);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getSeller');
            ResponseService::errorResponse();
        }
    }

    public function addReviewReport(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'report_reason' => 'required|string',
            'seller_review_id' => 'required',
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $ratings = SellerRating::where('seller_id', Auth::user()->id)->findOrFail($request->seller_review_id);
            $ratings->update([
                'report_status' => 'reported',
                'report_reason' => $request->report_reason,
            ]);

            ResponseService::successResponse(__('Your report has been submitted successfully.'), $ratings);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> addReviewReport');
            ResponseService::errorResponse();
        }
    }

    public function getVerificationFields()
    {
        try {
            $fields = VerificationField::all();
            ResponseService::successResponse(__('Verification Field Fetched Successfully'), $fields);
        } catch (Throwable $th) {
            DB::rollBack();
            ResponseService::logErrorResponse($th, 'API Controller -> addVerificationFieldValues');
            ResponseService::errorResponse();
        }
    }

    public function sendVerificationRequest(Request $request)
    {
        try {

            $validator = Validator::make($request->all(), [
                'verification_field' => 'sometimes|array',
                'verification_field.*' => 'sometimes',
                'verification_field_files' => 'nullable|array',
                'verification_field_files.*' => 'nullable|mimes:jpeg,png,jpg,pdf,doc|max:7168',
                'verification_field_translations' => 'nullable|json',

            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            DB::beginTransaction();

            $user = Auth::user();
            $verificationRequest = VerificationRequest::updateOrCreate([
                'user_id' => $user->id,
            ], ['status' => 'pending']);

            $user = auth()->user();
            if ($request->verification_field) {
                $itemCustomFieldValues = [];
                foreach ($request->verification_field as $id => $value) {
                    $itemCustomFieldValues[] = [
                        'user_id' => $user->id,
                        'verification_field_id' => $id,
                        'verification_request_id' => $verificationRequest->id,
                        'value' => $value,
                        'created_at' => now(),
                        'updated_at' => now(),
                    ];
                }
                if (count($itemCustomFieldValues) > 0) {
                    VerificationFieldValue::upsert($itemCustomFieldValues, ['user_id', 'verification_fields_id'], ['value', 'updated_at']);
                }
            }

            if ($request->verification_field_files) {
                $itemCustomFieldValues = [];
                foreach ($request->verification_field_files as $fieldId => $file) {
                    $itemCustomFieldValues[] = [
                        'user_id' => $user->id,
                        'verification_field_id' => $fieldId,
                        'verification_request_id' => $verificationRequest->id,
                        'value' => ! empty($file) ? FileService::upload($file, 'verification_field_files') : '',
                        'created_at' => now(),
                        'updated_at' => now(),
                    ];
                }
                if (count($itemCustomFieldValues) > 0) {
                    VerificationFieldValue::upsert($itemCustomFieldValues, ['user_id', 'verification_field_id'], ['value', 'updated_at']);
                }
            }
            if ($request->has('verification_field_translations')) {
                $fieldTranslations = json_decode($request->input('verification_field_translations'), true, 512, JSON_THROW_ON_ERROR);
                $translatedEntries = [];

                foreach ($fieldTranslations as $languageId => $fieldsById) {
                    foreach ($fieldsById as $fieldId => $translatedValue) {
                        $translatedEntries[] = [
                            'user_id' => $user->id,
                            'verification_field_id' => $fieldId,
                            'verification_request_id' => $verificationRequest->id,
                            'language_id' => $languageId,
                            'value' => is_array($translatedValue) ? implode(',', $translatedValue) : $translatedValue,
                            'created_at' => now(),
                            'updated_at' => now(),
                        ];
                    }
                }

                if (! empty($translatedEntries)) {
                    // upsert to avoid duplicates — if necessary
                    VerificationFieldValue::upsert(
                        $translatedEntries,
                        ['user_id', 'verification_field_id'],
                        ['value', 'updated_at', 'language_id']
                    );
                }
            }

            DB::commit();

            ResponseService::successResponse(__('Verification request submitted successfully.'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> SendVerificationRequest');
            ResponseService::errorResponse();
        }
    }

    public function getVerificationRequest(Request $request)
    {
        try {
            $verificationRequest = VerificationRequest::with([
                'verification_field_values.verification_field.translations',
            ])->owner()->first();

            if (empty($verificationRequest)) {
                ResponseService::errorResponse('No Request found');
            }

            $response = $verificationRequest->toArray();
            $response['verification_fields'] = [];

            // Get current language for translation
            $contentLangCode = $request->header('Content-Language') ?? app()->getLocale();
            $currentLanguage = Language::where('code', $contentLangCode)->first();
            $currentLangId = $currentLanguage->id ?? 1;

            foreach ($verificationRequest->verification_field_values as $verificationFieldValue) {
                if (
                    $verificationFieldValue->relationLoaded('verification_field') &&
                    ! empty($verificationFieldValue->verification_field)
                ) {

                    // if (empty($verificationFieldValue->language_id) || $verificationFieldValue->language_id = null) {
                    //     $verificationFieldValue->language_id = $currentLangId;
                    // }

                    $field = $verificationFieldValue->verification_field;
                    $tempRow = $field->toArray();

                    $rawValue = $verificationFieldValue->value;

                    // Normalize value to array
                    $normalizedValue = [];
                    if ($field->type === 'fileinput') {
                        $normalizedValue = ! empty($rawValue) ? [url(Storage::url($rawValue))] : [];
                    } elseif (is_array($rawValue)) {
                        $normalizedValue = $rawValue;
                    } elseif (is_string($rawValue)) {
                        $decoded = json_decode($rawValue, true);
                        if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                            $normalizedValue = $decoded;
                        } else {
                            $normalizedValue = [$rawValue];
                        }
                    } elseif (! empty($rawValue)) {
                        $normalizedValue = [$rawValue];
                    }

                    // Set normalized value
                    $tempRow['value'] = array_map('trim', explode(',', $normalizedValue[0]));

                    // Set verification_field_value with normalized value
                    $tempRow['verification_field_value'] = $verificationFieldValue->toArray();
                    unset($tempRow['verification_field_value']['verification_field']);
                    $tempRow['verification_field_value']['value'] = $normalizedValue;
                    $tempRow['verification_field_value']['language_id'] = $verificationFieldValue->language_id;
                    // Handle translated_selected_values
                    $selected = [];
                    $type = $field->type ?? null;
                    $allPossibleValues = $field->values ?? [];

                    // Fetch translated values (if available)
                    $translatedValues = [];
                    if (! empty($field->translations)) {
                        $translation = collect($field->translations)->firstWhere('language_id', $currentLangId);
                        $translatedValues = $translation['value'] ?? [];
                    }
                    if (empty($translatedValues)) {
                        $translatedValues = $allPossibleValues;
                    }

                    if (in_array($type, ['checkbox', 'radio', 'dropdown'])) {
                        foreach ($normalizedValue as $val) {
                            $index = array_search($val, $allPossibleValues);
                            $translatedVal = ($index !== false && isset($translatedValues[$index]))
                                ? $translatedValues[$index]
                                : $val;
                            $selected[] = $translatedVal;
                        }
                    } elseif (in_array($type, ['textbox', 'number'])) {
                        $selected = $normalizedValue;
                    }
                    $tempRow['language_id'] = $verificationFieldValue->language_id;
                    $tempRow['translated_selected_values'] = $selected;
                    $response['verification_fields'][] = $tempRow;
                }
            }

            ResponseService::successResponse(__('Verification request fetched successfully.'), $response);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> SendVerificationRequest');
            ResponseService::errorResponse();
        }
    }

    public function seoSettings(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'page' => 'nullable',
            ]);

            if ($validator->fails()) {
                ResponseService::validationError($validator->errors()->first());
            }
            $settings = new SeoSetting;
            if (! empty($request->page)) {
                $settings = $settings->where('page', $request->page);
            }

            $settings = $settings->get();
            ResponseService::successResponse(__('SEO settings fetched successfully.'), $settings);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> seoSettings');
            ResponseService::errorResponse();
        }
    }

    public function getCategories(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'language_code' => 'nullable',
        ]);

        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            $categories = Category::all();
            $languageCode = $request->get('language_code', 'en');

            $translator = new GoogleTranslate($languageCode);
            $categoriesJson = $categories->toJson();
            $translatedJson = $translator->translate($categoriesJson);
            $translatedCategories = json_decode($translatedJson, true);

            return ResponseService::successResponse(null, $translatedCategories);
            ResponseService::successResponse(null, $sql);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategories');
            ResponseService::errorResponse();
        }
    }

    public function bankTransferUpdate(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'payment_transection_id' => 'required|integer',
                'payment_receipt' => 'required|file|mimes:jpg,jpeg,png|max:7048',
            ]);

            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }
            $transaction = PaymentTransaction::where('user_id', Auth::user()->id)->findOrFail($request->payment_transection_id);

            if (! $transaction) {
                return ResponseService::errorResponse(__('Transaction not found.'));
            }
            $receiptPath = ! empty($request->file('payment_receipt'))
                ? FileService::upload($request->file('payment_receipt'), 'bank-transfer')
                : '';
            $transaction->update([
                'payment_receipt' => $receiptPath,
                'payment_status' => 'under review',
            ]);

            return ResponseService::successResponse(__('Payment transaction updated successfully.'), $transaction);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> bankTransferUpdate');

            return ResponseService::errorResponse();
        }
    }
    public function getOtp(Request $request)
    {
        try {
            $validator = Validator::make($request->query(), [
                'country_code' => 'required|string|max:5',
                'number' => 'required|string|max:15',
            ]);

            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }

            // Normalize inputs
            $countryCode = ltrim(trim($request->query('country_code')), '+');
            $number = preg_replace('/\D/', '', $request->query('number'));

            $toNumber = '+' . $countryCode . $number;

            $twilioSettings = Setting::whereIn('name', [
                'twilio_account_sid',
                'twilio_auth_token',
                'twilio_my_phone_number',
            ])->pluck('value', 'name');

            if ($twilioSettings->count() < 3) {
                return ResponseService::errorResponse(__('Twilio settings are missing.'));
            }

            $client = new TwilioRestClient(
                $twilioSettings['twilio_account_sid'],
                $twilioSettings['twilio_auth_token']
            );

            try {
                $client->lookups->v1->phoneNumbers($toNumber)->fetch();
            } catch (\Throwable $e) {
                return ResponseService::errorResponse(__('Invalid phone number.'));
            }

            $otp = rand(100000, 999999);
            $expireAt = now()->addMinutes(10);

            NumberOtp::updateOrCreate(
                [
                    'number' => $number,
                ],
                [
                    'otp' => $otp,
                    'expire_at' => $expireAt,
                ]
            );

            // Send OTP
            $client->messages->create($toNumber, [
                'from' => $twilioSettings['twilio_my_phone_number'],
                'body' => "Your OTP is: $otp. It expires in 10 minutes.",
            ]);

            return ResponseService::successResponse(__('OTP sent successfully.'));
        } catch (\Throwable $th) {
            ResponseService::logErrorResponse($th, 'OTP Controller -> getOtp');

            return ResponseService::errorResponse();
        }
    }

   public function verifyOtp(Request $request)
    {
        try {
            $validator = Validator::make($request->all(), [
                'number' => 'required|string',
                'country_code' => 'required|string',
                'otp' => 'required|numeric|digits:6',
                'password' => 'nullable|string|min:6',
            ]);

            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }

            $number = $request->query('number');
            $countryCode = $request->query('country_code');

            // Format full phone number
            // $requestNumber = $countryCode.$number;

            // $trimmedNumber = ltrim($requestNumber, '+');
            // $toNumber = '+'.$trimmedNumber;

            $otpRecord = NumberOtp::where('number', $number)->first();
            if (! $otpRecord) {
                return ResponseService::errorResponse(__('OTP not found.'));
            }
            if (now()->isAfter($otpRecord->expire_at)) {
                return ResponseService::validationError(__('OTP has expired.'));
            }

            if ($otpRecord->attempts >= 3) {
                $otpRecord->delete();

                return ResponseService::validationError(__('OTP expired after 3 failed attempts.'));
            }

            if ($otpRecord->otp != $request->otp) {
                $otpRecord->increment('attempts');

                return ResponseService::validationError(__('Invalid OTP.'));
            }
            $otpRecord->delete();

            $user = User::where('mobile', $request->number)->where('type', 'phone')->first();

            if (! $user) {
                $user = User::create([
                    'mobile' => $request->number,
                    'type' => 'phone',
                    'country_code' => $countryCode,
                    'password' => ! empty($request->password) ? Hash::make($request->password) : '',
                ]);
                $user->assignRole('User');
            }else{
                if (! empty($countryCode)) {
                    $user->country_code = ltrim($countryCode, '+');
                }
                $user->save();
            }

            Auth::login($user);
            $auth = User::find(Auth::id());

            $token = $auth->createToken($auth->name ?? '')->plainTextToken;

            return ResponseService::successResponse(__('User logged-in successfully'), $auth, ['token' => $token]);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'OTP Controller -> verifyOtp');

            return ResponseService::errorResponse();
        }
    }
    public function userExists(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'mobile' => 'required|string',
            'country_code' => 'required|string',
            'forgot_password' => 'nullable|boolean',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }

        try {
            $mobile = ltrim($request->mobile, '+');
            $countryCode = ltrim($request->country_code, '+');
            $mobileWithCode = $countryCode . $mobile;
            $userExists = User::where('type', 'phone')
                    ->where('mobile', $mobile)
                    ->withTrashed()
                    ->first();
                
                if (! $userExists) {
                    return ResponseService::errorResponse(
                        __('User does not exist'),
                        ['user_exists' => false]
                    );
                }

                // ❌ user found but deactivated
                if ($userExists->deleted_at) {
                    return ResponseService::errorResponse(
                        __('User is deactivated. Please contact the administrator.'),
                        ['user_exists' => false]
                    );
                }
            if ($userExists) {
                return ResponseService::successResponse(
                    __('User already exists'),
                    ['user_exists' => true]
                );
            }

            return ResponseService::errorResponse(
                __('User does not exist'),
                ['user_exists' => false]
            );

        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> userExists');
            return ResponseService::errorResponse();
        }
    }
    public function applyJob(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_id' => 'required',
            'full_name' => 'required|string|max:255',
            'email' => 'required|email|max:255',
            'mobile' => 'required|string|max:20',
            'resume' => 'nullable|file|mimes:pdf,doc,docx|max:7168',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }

        try {
            $userId = Auth::id();
            $post = Item::approved()->notOwner()->findOrFail($request->item_id);
            $alreadyApplied = JobApplication::where('item_id', $request->item_id)
                ->where('user_id', $userId)
                ->exists();

            if ($alreadyApplied) {
                return ResponseService::validationError(__('You have already applied for this job.'));
            }
            $resumePath = null;
            if ($request->hasFile('resume')) {
                $resumePath = FileService::upload($request->resume, 'job_resume');
            }

            $application = JobApplication::create([
                'item_id' => $post->id,
                'user_id' => Auth::user()->id,
                'recruiter_id' => $post->user_id,
                'full_name' => $request->full_name,
                'email' => $request->email,
                'mobile' => $request->mobile,
                'resume' => $resumePath,
            ]);

            $user_token = UserFcmToken::where('user_id', $post->user_id)->pluck('fcm_token')->toArray();
            if (! empty($user_token)) {
                NotificationService::sendFcmNotification(
                    $user_token,
                    'New Job Application',
                    $request->full_name . ' applied for your job post: ' . $post->name,
                    'job-application',
                    ['item_id' => $post->id]
                );
            }

            return ResponseService::successResponse(__('Application submitted successfully.'), $application);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> applyJob');

            return ResponseService::errorResponse();
        }
    }

    public function recruiterApplications(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_id' => 'nullable|integer',
            'page' => 'nullable|integer',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }
        try {
            $user = Auth::user();

            $applications = JobApplication::where('recruiter_id', $user->id)
                ->with('user:id,name,email', 'item:id,name');
            if (! empty($request->item_id)) {
                $applications->where('item_id', $request->item_id);
            }

            $applications = $applications->latest()->paginate();

            return ResponseService::successResponse(__('Recruiter applications fetched'), $applications);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> recruiterApplications');

            return ResponseService::errorResponse();
        }
    }

    public function myJobApplications(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'item_id' => 'nullable|integer',
            'page' => 'nullable|integer',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }
        try {
            $user = Auth::user();

            $applications = JobApplication::where('user_id', $user->id);

            if (! empty($request->item_id)) {
                $applications->where('item_id', $request->item_id);
            }

            $applications = $applications->with([
                'item:id,name,user_id',
                'recruiter:id,name,email',
            ])
                ->latest()
                ->paginate();

            return ResponseService::successResponse(__('Your job applications fetched'), $applications);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> myJobApplications');

            return ResponseService::errorResponse();
        }
    }

    public function updateJobStatus(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'job_id' => 'required|exists:job_applications,id',
            'status' => 'required|in:accepted,rejected',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }

        try {
            $user = Auth::user();
            $application = JobApplication::with('item')->findOrFail($request->job_id);

            if ($application->recruiter_id !== $user->id) {
                return ResponseService::errorResponse(__('Unauthorized to update this job status.'), 403);
            }

            $application->update(['status' => $request->status]);

            // Optional: Notify the applicant
            $user_token = UserFcmToken::where('user_id', $application->user_id)->pluck('fcm_token')->toArray();
            if (! empty($user_token)) {
                NotificationService::sendFcmNotification(
                    $user_token,
                    'Application ' . ucfirst($request->status),
                    'Your application for job post has been ' . $request->status,
                    'application-status',
                    ['job_id' => $application->id]
                );
            }

            return ResponseService::successResponse(__('Application status updated.'), $application);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> updateJobStatus');

            return ResponseService::errorResponse();
        }
    }

    public function getLocationFromCoordinates(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'lat' => 'nullable|numeric',
            'lng' => 'nullable|numeric',
            'lang' => 'nullable|string',
            'search' => 'nullable|string',
            'place_id' => 'nullable|string',
            'session_id' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return ResponseService::validationError($validator->errors()->first());
        }

        try {
            $lat = $request->lat;
            $lng = $request->lng;
            $lang = $request->lang ?? 'en';
            $search = $request->search;
            $placeId = $request->place_id;
            $mapProvider = Setting::where('name', 'map_provider')->value('value') ?? 'free_api';

            // Determine current language ID
            $contentLangCode = $request->header('Content-Language') ?? app()->getLocale();
            $currentLanguage = Language::where('code', $contentLangCode)->first();
            $currentLangId = $currentLanguage->id ?? 1;

            /**
             * 🔍 Handle search query
             */
            if ($search) {
                if ($mapProvider === 'google_places') {
                    $apiKey = Setting::where('name', 'place_api_key')->value('value');
                    if (! $apiKey) {
                        return ResponseService::errorResponse(__('Google Maps API key not set'));
                    }

                    $response = Http::get('https://maps.googleapis.com/maps/api/place/autocomplete/json', [
                        'key' => $apiKey,
                        'input' => $search,
                        'language' => $lang,
                        'sessiontoken' => $request->session_id, // ✅ added
                    ]);

                    return $response->successful()
                        ? ResponseService::successResponse(__('Location fetched from Google API'), $response->json())
                        : ResponseService::errorResponse(__('Failed to fetch from Google Maps API'));
                } else {
                    // Search Areas with translations
                    $areas = Area::with([
                        'translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'city.translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'city.state.translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'city.state.country.nametranslations' => fn($q) => $q->where('language_id', $currentLangId),
                    ])
                        ->where('name', 'like', "%{$search}%")
                        ->limit(10)
                        ->get();

                    if ($areas->isNotEmpty()) {
                        return ResponseService::successResponse(__('Matching areas found'), $areas->map(function ($area) {
                            return [
                                'area_id' => $area->id,
                                'area' => $area->name,
                                'area_translation' => optional($area->translations->first())->name ?? $area->name,
                                'city_id' => optional($area->city)->id,
                                'city' => optional($area->city)->name,
                                'city_translation' => optional($area->city->translations->first())->name ?? optional($area->city)->name,
                                'state' => optional($area->city->state)->name,
                                'state_translation' => optional($area->city->state->translations->first())->name ?? optional($area->city->state)->name,
                                'country' => optional($area->city->state->country)->name,
                                'country_translation' => optional($area->city->state->country->nametranslations->first())->name ?? optional($area->city->state->country)->name,
                                'latitude' => $area->latitude,
                                'longitude' => $area->longitude,
                            ];
                        }));
                    }

                    // Search Cities with translations
                    $cities = City::with([
                        'translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'state.translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'state.country.nametranslations' => fn($q) => $q->where('language_id', $currentLangId),
                    ])
                        ->where('name', 'like', "%{$search}%")
                        ->orWhereHas('state', fn($q) => $q->where('name', 'like', "%{$search}%"))
                        ->orWhereHas('state.country', fn($q) => $q->where('name', 'like', "%{$search}%"))
                        ->limit(10)
                        ->get();

                    if ($cities->isEmpty()) {
                        return ResponseService::errorResponse(__('No matching location found'));
                    }

                    return ResponseService::successResponse(__('Matching cities found'), $cities->map(function ($city) {
                        return [
                            'city_id' => $city->id,
                            'city' => $city->name,
                            'city_translation' => optional($city->translations->first())->name ?? $city->name,
                            'state' => optional($city->state)->name,
                            'state_translation' => optional($city->state->translations->first())->name ?? optional($city->state)->name,
                            'country' => optional($city->state->country)->name,
                            'country_translation' => optional($city->state->country->nametranslations->first())->name ?? optional($city->state->country)->name,
                            'latitude' => $city->latitude,
                            'longitude' => $city->longitude,
                        ];
                    }));
                }
            }

            /**
             * 📍 Get location by coordinates
             */
            if (! empty($lat) && ! empty($lng)) {
                if ($mapProvider === 'google_places') {
                    $apiKey = Setting::where('name', 'place_api_key')->value('value');
                    if (! $apiKey) {
                        return ResponseService::errorResponse(__('Google Maps API key not set'));
                    }

                    $response = Http::get('https://maps.googleapis.com/maps/api/geocode/json', [
                        'latlng' => "{$lat},{$lng}",
                        'key' => $apiKey,
                        'language' => $lang,
                        'sessiontoken' => $request->session_id, // ✅ added
                    ]);

                    return $response->successful()
                        ? ResponseService::successResponse(__('Location fetched from Google API'), $response->json())
                        : ResponseService::errorResponse(__('Failed to fetch from Google Maps API'));
                } else {

                    $closestCity = City::with([
                        'translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'state.translations' => fn($q) => $q->where('language_id', $currentLangId),
                        'state.country.nametranslations' => fn($q) => $q->where('language_id', $currentLangId),
                    ])
                        ->whereNotNull('latitude')
                        ->whereNotNull('longitude')
                        ->selectRaw('
                        id, name, latitude, longitude, state_id,
                        (6371 * acos(cos(radians(?))
                            * cos(radians(latitude))
                            * cos(radians(longitude) - radians(?))
                            + sin(radians(?))
                            * sin(radians(latitude)))) AS distance
                    ', [$lat, $lng, $lat])
                        ->orderBy('distance', 'asc')
                        ->first();

                    if (! $closestCity) {
                        return ResponseService::errorResponse(__('No nearby city found'));
                    }

                    $closestArea = Area::with([
                        'translations' => fn($q) => $q->where('language_id', $currentLangId),
                    ])
                        ->where('city_id', $closestCity->id)
                        ->whereNotNull('latitude')
                        ->whereNotNull('longitude')
                        ->selectRaw('
                        id, name, latitude, longitude, city_id,
                        (6371 * acos(cos(radians(?))
                            * cos(radians(latitude))
                            * cos(radians(longitude) - radians(?))
                            + sin(radians(?))
                            * sin(radians(latitude)))) AS distance
                    ', [$lat, $lng, $lat])
                        ->orderBy('distance', 'asc')
                        ->first();

                    return ResponseService::successResponse(__('Location fetched from local database'), [
                        'city_id' => $closestCity->id,
                        'city' => $closestCity->name,
                        'city_translation' => optional($closestCity->translations->first())->name ?? $closestCity->name,
                        'state' => optional($closestCity->state)->name,
                        'state_translation' => optional($closestCity->state->translations->first())->name ?? optional($closestCity->state)->name,
                        'country' => optional($closestCity->state->country)->name,
                        'country_translation' => optional($closestCity->state->country->nametranslations->first())->name ?? optional($closestCity->state->country)->name,
                        'area_id' => optional($closestArea)->id,
                        'area' => optional($closestArea)->name,
                        'area_translation' => optional($closestArea?->translations?->first())->name ?? $closestArea?->name,
                        'latitude' => $closestCity->latitude,
                        'longitude' => $closestCity->longitude,
                    ]);
                }
            }

            /**
             * 🏷️ Handle place_id
             */
            if ($placeId) {
                if ($mapProvider === 'google_places') {
                    $apiKey = Setting::where('name', 'place_api_key')->value('value');
                    if (! $apiKey) {
                        return ResponseService::errorResponse(__('Google Maps API key not set'));
                    }
                    $sessionParam = $request->session_id ? "&sessiontoken={$request->session_id}" : '';
                    $url = "https://maps.googleapis.com/maps/api/geocode/json?place_id={$placeId}&key={$apiKey}&language={$lang}{$sessionParam}";

                    // $url = "https://maps.googleapis.com/maps/api/geocode/json?place_id={$placeId}&key={$apiKey}&language={$lang}";
                    $response = Http::get($url);

                    return $response->successful()
                        ? ResponseService::successResponse(__('Location fetched from place_id'), $response->json())
                        : ResponseService::errorResponse(__('Failed to fetch from Google Maps API using place_id'));
                } else {
                    return ResponseService::errorResponse(__('place_id is only supported with Google Maps provider'));
                }
            }
        } catch (\Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getLocationFromCoordinates');

            return ResponseService::errorResponse(__('Failed to fetch location'));
        }
    }

    public function subscribeFCMTopic(Request $request)
    {
        $request->validate([
            'fcm_token' => 'required|string',
            'topic' => 'required|string',
        ]);

        $serverKey = env('FIREBASE_SERVER_KEY'); // legacy server key
        $url = "https://iid.googleapis.com/iid/v1/{$request->fcm_token}/rel/topics/{$request->topic}";

        $response = \Illuminate\Support\Facades\Http::withHeaders([
            'Authorization' => 'key=' . $serverKey,
            'access_token_auth' => true,
            'Content-Type' => 'application/json',
        ])->post($url);

        if ($response->successful()) {
            return response()->json(['error' => false, 'message' => 'Subscribed successfully']);
        }

        return response()->json(['error' => true, 'details' => $response->body()], $response->status());
    }

    public function getItemSlugs(Request $request)
    {
        try {
            $items = Item::without('translations')
                ->select('id', 'slug', 'updated_at')
                ->where('status', 'approved')
                ->whereNull('deleted_at')
                ->getNonExpiredItems()
                ->get()
                ->each->setAppends([]);

            if ($items->isEmpty()) {
                return ResponseService::errorResponse(__('No active items found.'));
            }

            return ResponseService::successResponse(__('Active item slugs fetched successfully.'), $items);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getItemSlugs');

            return ResponseService::errorResponse();
        }
    }

    public function getCategoriesSlug(Request $request)
    {
        try {
            $categories = Category::without('translations')
                ->select('id', 'slug', 'updated_at')
                ->where('status', 1)
                ->get()
                ->each->setAppends([]);

            if ($categories->isEmpty()) {
                return ResponseService::errorResponse(__('No active Categories found.'));
            }

            return ResponseService::successResponse(__('Active Categories slugs fetched successfully.'), $categories);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategoriesSlug');
            ResponseService::errorResponse();
        }
    }

    public function getBlogsSlug(Request $request)
    {
        try {
            $blogs = Blog::without('translations')
                ->select('id', 'slug', 'updated_at')
                ->get()
                ->each->setAppends([]);

            if ($blogs->isEmpty()) {
                return ResponseService::errorResponse(__('No active Blogs found.'));
            }

            return ResponseService::successResponse(__('Active Blogs slugs fetched successfully.'), $blogs);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategoriesSlug');
            ResponseService::errorResponse();
        }
    }

    public function getFeatureSectionSlug(Request $request)
    {
        try {
            $FeatureSection = FeatureSection::without('translations')
                ->select('id', 'slug', 'updated_at')
                ->get()
                ->each->setAppends([]);

            if ($FeatureSection->isEmpty()) {
                return ResponseService::errorResponse(__('No active Feature Sections found.'));
            }

            return ResponseService::successResponse(__('Active Feature Sections slugs fetched successfully.'), $FeatureSection);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategoriesSlug');
            ResponseService::errorResponse();
        }
    }

    public function logout(Request $request)
    {
        try {
            $user = Auth::user();
            $validator = Validator::make($request->all(), [
                'fcm_token' => 'nullable|string',
            ]);

            if ($validator->fails()) {
                return ResponseService::validationError($validator->errors()->first());
            }
            if ($request->fcm_token) {
                UserFcmToken::where('user_id', $user->id)
                    ->where('fcm_token', $request->fcm_token)
                    ->delete();
            }

            return ResponseService::successResponse(__('User logged out successfully'));
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> Logout');

            return ResponseService::errorResponse();
        }
    }

    public function getSellerSlug(Request $request)
    {
        try {
            $sellers = user::select('id', 'updated_at')
                ->whereNull('deleted_at')
                ->get();

            if ($sellers->isEmpty()) {
                return ResponseService::errorResponse(__('No active seller found.'));
            }

            return ResponseService::successResponse(__('Active Seller fetched successfully.'), $sellers);
        } catch (Throwable $th) {
            ResponseService::logErrorResponse($th, 'API Controller -> getCategoriesSlug');
            ResponseService::errorResponse();
        }
    }
}
