<?php

namespace App\Http\Controllers;

use App\Models\Page;
use App\Models\Post;
use App\Models\User;
use App\Models\Group;
use App\Models\Friend;
use App\Models\PageLike;
use App\Models\GroupMember;
use Illuminate\Http\Request;
use App\Models\SearchAnalytics;
use Illuminate\Support\Facades\DB;
use App\Http\Resources\PostResource;
use App\Http\Resources\UserResource;
use Illuminate\Support\Facades\Auth;
use App\Http\Resources\GroupResource;
use Illuminate\Support\Facades\Cache;

class UnifiedSearchController extends Controller
{
    /**
     * Unified search across users, posts, and groups
     */
    public function search(Request $request)
    {
        $request->validate([
            'query' => 'required|string|min:1|max:255',
            'type' => 'nullable|in:users,posts,groups,pages,all',
            'limit' => 'nullable|integer|min:1|max:50',
            'offset' => 'nullable|integer|min:0',
            'filters' => 'nullable|array',
            'filters.date_from' => 'nullable|date',
            'filters.date_to' => 'nullable|date',
            'filters.location' => 'nullable|string|max:255',
            'filters.popularity' => 'nullable|in:high,medium,low',
            'filters.verified_only' => 'nullable|boolean',
            'filters.friends_only' => 'nullable|boolean',
            'sort_by' => 'nullable|in:relevance,date,popularity,alphabetical',
        ]);

        $query = trim($request->input('query'));
        $type = $request->input('type', 'all');
        $limit = $request->input('limit', 20);
        $offset = $request->input('offset', 0);
        $filters = $request->input('filters', []);
        $sortBy = $request->input('sort_by', 'relevance');

        $user = Auth::user(); // Can be null for unauthenticated requests
        $results = [];
        $totalResults = 0;

        try {
            // Create cache key for performance optimization
            $userId = $user ? $user->id : 'guest';
            $cacheKey = $this->generateCacheKey($query, $type, $filters, $sortBy, $userId, $limit, $offset);

            $results = Cache::remember($cacheKey, 300, function () use ($query, $type, $limit, $offset, $filters, $sortBy, $user) {
                $searchResults = [];

                if ($type === 'all' || $type === 'users') {
                    $searchResults['users'] = $this->searchUsers($query, $limit, $offset, $filters, $sortBy, $user);
                }

                if ($type === 'all' || $type === 'posts') {
                    $searchResults['posts'] = $this->searchPosts($query, $limit, $offset, $filters, $sortBy, $user);
                }

                if ($type === 'all' || $type === 'groups') {
                    $searchResults['groups'] = $this->searchGroups($query, $limit, $offset, $filters, $sortBy, $user);
                }
                if ($type === 'all' || $type === 'pages') {
                    $searchResults['pages'] = $this->searchPages($query, $limit, $offset, $filters, $sortBy, $user);
                }

                return $searchResults;
            });

            // Calculate total results
            $totalResults = collect($results)->sum(function ($items) {
                return is_countable($items) ? count($items) : 0;
            });

            // Log search analytics (async to avoid slowing down response)
            if ($user) {
                $this->logSearchAnalytics($user->id, $query, $type, $filters, $totalResults, $request);
            }

            return response()->json([
                'status' => 200,
                'message' => 'Search results retrieved successfully.',
                'data' => [
                    'query' => $query,
                    'results' => $results,
                    'meta' => [
                        'total_users' => isset($results['users']) ? count($results['users']) : 0,
                        'total_posts' => isset($results['posts']) ? count($results['posts']) : 0,
                        'total_groups' => isset($results['groups']) ? count($results['groups']) : 0,
                        'total_pages' => isset($results['pages']) ? count($results['pages']) : 0,

                        'total_results' => $totalResults,
                        'search_type' => $type,
                        'applied_filters' => $filters,
                        'sort_by' => $sortBy,
                        'limit' => $limit,
                        'offset' => $offset,
                    ]
                ]
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'An error occurred while searching.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error'
            ], 500);
        }
    }

    /**
     * Search users with fuzzy matching and relevance scoring
     */
    private function searchUsers($query, $limit, $offset, $filters, $sortBy, $user)
    {
        $userQuery = User::query()
            ->select([
                'id',
                'username',
                'first_name',
                'last_name',
                'name',
                'email',
                'bio',
                'avatar',
                'status',
                'last_seen',
                'created_at',
                'login_count'
            ])
            ->where('status', 1)
            ->whereNull('deleted_at');

        // Apply search filters with relevance scoring
        $userQuery->where(function ($q) use ($query) {
            $q->where('username', 'LIKE', "%{$query}%")
                ->orWhere('first_name', 'LIKE', "%{$query}%")
                ->orWhere('last_name', 'LIKE', "%{$query}%")
                ->orWhere('name', 'LIKE', "%{$query}%")
                ->orWhere('email', 'LIKE', "%{$query}%")
                ->orWhere('bio', 'LIKE', "%{$query}%");
        });

        // Add relevance scoring using CASE WHEN for better ranking
        $userQuery->selectRaw("
            CASE 
                WHEN username = '" . addslashes($query) . "' THEN 100
                WHEN username LIKE '" . addslashes($query) . "%' THEN 90
                WHEN CONCAT(first_name, ' ', last_name) = '" . addslashes($query) . "' THEN 85
                WHEN first_name = '" . addslashes($query) . "' OR last_name = '" . addslashes($query) . "' THEN 80
                WHEN name = '" . addslashes($query) . "' THEN 75
                WHEN username LIKE '%" . addslashes($query) . "%' THEN 70
                WHEN first_name LIKE '%" . addslashes($query) . "%' OR last_name LIKE '%" . addslashes($query) . "%' THEN 60
                WHEN name LIKE '%" . addslashes($query) . "%' THEN 55
                WHEN email LIKE '%" . addslashes($query) . "%' THEN 50
                WHEN bio LIKE '%" . addslashes($query) . "%' THEN 40
                ELSE 30
            END as relevance_score
        ");

        // Apply additional filters
        if (isset($filters['friends_only']) && $filters['friends_only'] && $user) {
            $friendIds = $this->getFriendIds($user);
            if (!empty($friendIds)) {
                $userQuery->whereIn('id', $friendIds);
            } else {
                return []; // No friends found
            }
        }

        if (isset($filters['verified_only']) && $filters['verified_only']) {
            $userQuery->whereNotNull('email_verified_at');
        }

        if (isset($filters['location']) && !empty($filters['location'])) {
            $userQuery->where('address', 'LIKE', "%{$filters['location']}%");
        }

        if (isset($filters['date_from'])) {
            $userQuery->whereDate('created_at', '>=', $filters['date_from']);
        }

        if (isset($filters['date_to'])) {
            $userQuery->whereDate('created_at', '<=', $filters['date_to']);
        }

        // Apply sorting
        switch ($sortBy) {
            case 'alphabetical':
                $userQuery->orderBy('first_name')->orderBy('last_name');
                break;
            case 'date':
                $userQuery->orderBy('created_at', 'desc');
                break;
            case 'popularity':
                $userQuery->orderBy('login_count', 'desc');
                break;
            default: // relevance
                $userQuery->orderBy('relevance_score', 'desc')
                    ->orderBy('last_seen', 'desc');
        }

        $users = $userQuery->skip($offset)->take($limit)->get();

        return UserResource::collection($users);
    }

    /**
     * Search posts with content matching and privacy filtering
     */
    private function searchPosts($query, $limit, $offset, $filters, $sortBy, $user)
    {
        $postQuery = Post::query()
            ->with(['user:id,username,first_name,last_name,avatar', 'parentPost.user:id,username,first_name,last_name,avatar'])
            ->where('status', 1)
            ->whereNull('deleted_at');

        // Apply privacy filters
        $postQuery->where(function ($q) use ($user) {
            $q->where('privacy_level', 1); // Public posts

            if ($user) {
                $q->orWhere(function ($subQ) use ($user) {
                    $subQ->where('user_id', $user->id); // User's own posts
                })
                    ->orWhere(function ($subQ) use ($user) {
                        // Friends' posts (privacy level 2)
                        $friendIds = $this->getFriendIds($user);
                        if (!empty($friendIds)) {
                            $subQ->where('privacy_level', 2)
                                ->whereIn('user_id', $friendIds);
                        }
                    });
            }
        });

        // Apply search filters with relevance scoring
        $postQuery->where(function ($q) use ($query) {
            $q->where('post_text', 'LIKE', "%{$query}%")
                ->orWhere('feeling_description', 'LIKE', "%{$query}%")
                ->orWhere('location', 'LIKE', "%{$query}%");
        });

        // Add relevance scoring
        $postQuery->selectRaw("posts.*, 
            CASE 
                WHEN post_text LIKE '%" . addslashes($query) . "%' THEN 100
                WHEN post_text LIKE '%" . addslashes($query) . "%' THEN 80
                WHEN feeling_description LIKE '%" . addslashes($query) . "%' THEN 60
                WHEN location LIKE '%" . addslashes($query) . "%' THEN 40
                ELSE 30
            END as relevance_score
        ");

        // Apply additional filters
        if (isset($filters['date_from'])) {
            $postQuery->whereDate('created_at', '>=', $filters['date_from']);
        }

        if (isset($filters['date_to'])) {
            $postQuery->whereDate('created_at', '<=', $filters['date_to']);
        }

        if (isset($filters['location']) && !empty($filters['location'])) {
            $postQuery->where('location', 'LIKE', "%{$filters['location']}%");
        }

        if (isset($filters['popularity'])) {
            switch ($filters['popularity']) {
                case 'high':
                    $postQuery->where('likes_count', '>=', 50);
                    break;
                case 'medium':
                    $postQuery->whereBetween('likes_count', [10, 49]);
                    break;
                case 'low':
                    $postQuery->where('likes_count', '<', 10);
                    break;
            }
        }

        // Apply sorting
        switch ($sortBy) {
            case 'date':
                $postQuery->orderBy('created_at', 'desc');
                break;
            case 'popularity':
                $postQuery->orderByRaw('(likes_count + comments_count + shares_count) DESC');
                break;
            case 'alphabetical':
                $postQuery->orderBy('post_text');
                break;
            default: // relevance
                $postQuery->orderBy('relevance_score', 'desc')
                    ->orderBy('created_at', 'desc');
        }

        $posts = $postQuery->skip($offset)->take($limit)->get();

        return PostResource::collection($posts);
    }

    /**
     * Search groups with membership and privacy considerations
     */
    private function searchGroups($query, $limit, $offset, $filters, $sortBy, $user)
    {
        $groupQuery = Group::query()
            ->with(['creator:id,username,first_name,last_name,avatar'])
            ->whereNull('deleted_at');

        // Apply search filters with relevance scoring
        $groupQuery->where(function ($q) use ($query) {
            $q->where('name', 'LIKE', "%{$query}%")
                ->orWhere('description', 'LIKE', "%{$query}%");
        });

        // Add relevance scoring with proper query binding

        // Apply privacy filters (show public groups and groups user is member of)
        $groupQuery->where(function ($q) use ($user) {
            $q->where('privacy', '=', 'public');

            if ($user) {
                $q->orWhereIn('id', function ($subQ) use ($user) {
                    $subQ->select('group_id')
                        ->from('group_members')
                        ->where('user_id', $user->id);
                });
            }
        });

        // Apply additional filters
        if (isset($filters['date_from'])) {
            $groupQuery->whereDate('created_at', '>=', $filters['date_from']);
        }

        if (isset($filters['date_to'])) {
            $groupQuery->whereDate('created_at', '<=', $filters['date_to']);
        }

        if (isset($filters['popularity'])) {
            switch ($filters['popularity']) {
                case 'high':
                    $groupQuery->where('members_count', '>=', 100);
                    break;
                case 'medium':
                    $groupQuery->whereBetween('members_count', [20, 99]);
                    break;
                case 'low':
                    $groupQuery->where('members_count', '<', 20);
                    break;
            }
        }

        // Apply sorting
        switch ($sortBy) {
            case 'alphabetical':
                $groupQuery->orderBy('name');
                break;
            case 'date':
                $groupQuery->orderBy('created_at', 'desc');
                break;
            case 'popularity':
                $groupQuery->orderBy('members_count', 'desc');
                break;
            default: // relevance
                $groupQuery
                    ->orderBy('members_count', 'desc');
        }

        $groups = $groupQuery->skip($offset)->take($limit)->get();

        return GroupResource::collection($groups);
    }
    private function searchPages($query, $limit, $offset, $filters, $sortBy, $user)
    {
        $groupQuery = Page::query()

            ->whereNull('deleted_at');

        // Apply search filters with relevance scoring
        $groupQuery->where(function ($q) use ($query) {
            $q->where('page_username', 'LIKE', "%{$query}%")
                ->orWhere('page_description', 'LIKE', "%{$query}%");
        });





        $pages = $groupQuery->skip($offset)->take($limit)->get();

        return GroupResource::collection($pages);
    }



    /**
     * Autocomplete suggestions endpoint
     */
    public function autocomplete(Request $request)
    {
        $request->validate([
            'query' => 'required|string|min:1|max:100',
            'limit' => 'nullable|integer|min:1|max:20',
        ]);

        $query = trim($request->input('query'));
        $limit = $request->input('limit', 10);
        $user = Auth::user();

        // Cache autocomplete results for better performance
        $userId = $user ? $user->id : 'guest';
        $cacheKey = "autocomplete:{$userId}:" . md5($query . $limit);

        $suggestions = Cache::remember($cacheKey, 60, function () use ($query, $limit, $user) {
            $suggestions = [];

            // User suggestions
            $users = User::where('status', 1)
                ->whereNull('deleted_at')
                ->where(function ($q) use ($query) {
                    $q->where('username', 'LIKE', "{$query}%")
                        ->orWhere('first_name', 'LIKE', "{$query}%")
                        ->orWhere('last_name', 'LIKE', "{$query}%");
                })
                ->select('id', 'username', 'first_name', 'last_name', 'avatar')
                ->limit($limit)
                ->get();

            foreach ($users as $userItem) {
                $suggestions[] = [
                    'type' => 'user',
                    'id' => $userItem->id,
                    'title' => trim($userItem->first_name . ' ' . $userItem->last_name),
                    'subtitle' => '@' . $userItem->username,
                    'avatar' => $userItem->avatar,
                ];
            }

            // Group suggestions
            $groups = Group::whereNull('deleted_at')
                ->where('privacy', '=', 'public')
                ->where('name', 'LIKE', "{$query}%")
                ->select('id', 'name', 'description', 'cover_image')
                ->limit($limit)
                ->get();

            foreach ($groups as $group) {
                $suggestions[] = [
                    'type' => 'group',
                    'id' => $group->id,
                    'title' => $group->name,
                    'subtitle' => \Str::limit($group->description ?? '', 50),
                    'avatar' => $group->cover_image,
                ];
            }

            return $suggestions;
        });

        return response()->json([
            'status' => 200,
            'message' => 'Autocomplete suggestions retrieved successfully.',
            'data' => $suggestions
        ]);
    }

    /**
     * Get trending searches
     */
    public function trending(Request $request)
    {
        $limit = $request->input('limit', 10);
        $days = $request->input('days', 7);

        try {
            $trending = SearchAnalytics::getTrendingSearches($limit, $days);

            return response()->json([
                'status' => 200,
                'message' => 'Trending searches retrieved successfully.',
                'data' => $trending
            ]);
        } catch (\Exception $e) {
            // Fallback to mock data if SearchAnalytics table doesn't exist yet
            $trending = [
                ['query' => 'technology', 'count' => 1250],
                ['query' => 'sports', 'count' => 890],
                ['query' => 'music', 'count' => 765],
                ['query' => 'travel', 'count' => 543],
                ['query' => 'food', 'count' => 432],
            ];

            return response()->json([
                'status' => 200,
                'message' => 'Trending searches retrieved successfully.',
                'data' => array_slice($trending, 0, $limit)
            ]);
        }
    }

    /**
     * Get search history for the authenticated user
     */
    public function history(Request $request)
    {
        $limit = $request->input('limit', 20);
        $user = Auth::user();

        try {
            $history = SearchAnalytics::getUserSearchHistory($user->id, $limit);

            return response()->json([
                'status' => 200,
                'message' => 'Search history retrieved successfully.',
                'data' => $history
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'Unable to retrieve search history.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error'
            ], 500);
        }
    }

    /**
     * Get search statistics (admin only)
     */
    public function stats(Request $request)
    {
        $user = Auth::user();

        // Check if user has admin role (adjust this based on your role system)
        if (!$user->hasRole('admin')) {
            return response()->json([
                'status' => 403,
                'message' => 'Unauthorized access.'
            ], 403);
        }

        $days = $request->input('days', 30);

        try {
            $stats = SearchAnalytics::getSearchStats($days);

            return response()->json([
                'status' => 200,
                'message' => 'Search statistics retrieved successfully.',
                'data' => $stats
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'Unable to retrieve search statistics.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error'
            ], 500);
        }
    }

    /**
     * Helper method to get friend IDs
     */
    private function getFriendIds($user)
    {
        return User::getFriends($user->id)->pluck('id')->toArray();
    }

    /**
     * Generate cache key for search results
     */
    private function generateCacheKey($query, $type, $filters, $sortBy, $userId, $limit, $offset)
    {
        return 'search:' . md5($query . $type . serialize($filters) . $sortBy . $userId . $limit . $offset);
    }

    /**
     * Log search analytics
     */
    private function logSearchAnalytics($userId, $query, $type, $filters, $resultsCount, $request)
    {
        try {
            SearchAnalytics::logSearch(
                $userId,
                $query,
                $type,
                $filters,
                $resultsCount,
                $request->ip(),
                $request->userAgent()
            );
        } catch (\Exception $e) {
            // Silently fail if analytics logging fails
            // This ensures search functionality continues to work even if analytics table doesn't exist
        }
    }
}
