<?php

namespace App\Http\Controllers;

use App\Models\Community;
use App\Models\RateMyPay;
use App\Models\User;
use App\Repositories\CommunityRepository;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\View\View;

class CommunityController extends Controller
{
    public function __construct(
        private CommunityRepository $communityRepository
    ) {}

    public function index(Request $request): View
    {
        // $filters = $request->only(['search']);
        // $communities = $this->communityRepository->getPaginatedCommunities($filters);
        
        // return view('communities.index', compact('communities'));

        $user = auth()->user();
        
        // Load user's communities with members count
        $userCommunities = $user->communities()
            ->withCount('members')
            ->orderBy('name')
            ->get();

        // Get recommended communities (not joined by user)
        $userJoinedCommunityIds = $userCommunities->pluck('id')->toArray();
        $recommendedCommunities = Community::whereNotIn('id', $userJoinedCommunityIds)
            ->withCount('members')
            ->orderBy('members_count', 'desc')
            ->take(4)
            ->get();

        // Get posts from user's communities
        $communityPosts = RateMyPay::whereHas('communities', function($query) use ($userJoinedCommunityIds) {
            $query->whereIn('communities.id', $userJoinedCommunityIds);
        })
        ->with(['user', 'jobExperience', 'communities', 'allComments.user', 'likes' => function ($query) use ($user) {
            $query->where('user_id', $user->id);
        }])
        ->withCount(['likes', 'comments', 'ratings'])
        ->orderBy('created_at', 'desc')
        ->get();

        // Get total count for the badge
        $totalCommunityPosts = $communityPosts->count();

        // Get user's published job experiences for the share button
        $userJobExperiences = $user->publishedJobs()->get();

        return view('communities.index', compact(
            'userCommunities',
            'recommendedCommunities',
            'communityPosts',
            'totalCommunityPosts',
            'userJobExperiences'
        ));
    }

    public function show(Request $request, Community $community): View
    {
        // $community->load(['members', 'posts.user', 'posts.jobExperience']);
        // Eager load community relations
        $community->load(['members']);
        
        // Start the Posts Query
        $query = $community->posts()
            ->with([
                'user', 
                'jobExperience', 
                'comments' => function($q) {
                    $q->orderBy('created_at', 'desc');
                }
            ]);
        
        // Apply Search Logic
        if ($request->filled('search')) {
            $search = $request->input('search');
            $query->where(function($q) use ($search) {
                // Search in Post Content
                $q->where('content', 'like', "%{$search}%")
                  // OR Search in Job Title / Company
                  ->orWhereHas('jobExperience', function($q2) use ($search) {
                      $q2->where('job_title', 'like', "%{$search}%")
                         ->orWhere('company_name', 'like', "%{$search}%")
                         ->orWhere('location', 'like', "%{$search}%");
                  });
            });
        }

        // DYNAMIC PAGINATION LOGIC
        // Get 'per_page' from URL, default to 10. Cap it at 100 to prevent crashes.
        $perPage = $request->input('per_page', 10);
        
        // Ensure perPage is an integer and within reasonable limits
        $perPage = is_numeric($perPage) ? min(max((int)$perPage, 5), 100) : 10;

        // Fetch posts
        $posts = $query->latest()->paginate($perPage)->withQueryString();
        // $posts = $this->communityRepository->getCommunityPosts($community, $filters);
        $members = $this->communityRepository->getCommunityMembers($community);
        $userRole = $this->communityRepository->getUserRoleInCommunity(auth()->user(), $community);
        $isMember = $this->communityRepository->userIsMember(auth()->user(), $community);

        // Get Job Experiences
        $experiences = auth()->user()->jobExperiences()->where('is_published', true)->get();

        $joinedCommunities = auth()->user()->communities()->orderBy('name', 'asc')->get(); 

        // If the current community isn't in the joined list (e.g. they are admin but not member), append it manually so it appears
        if (!$joinedCommunities->contains('id', $community->id)) {
            $joinedCommunities->push($community);
        }
            
        return view('dashboard.community.show', compact('community', 'posts', 'members', 'userRole', 'isMember', 'joinedCommunities', 'experiences'));
    }

    public function create(): View
    {
        return view('communities.create');
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255|unique:communities,name',
            'description' => 'required|string|max:1000',
            'category' => 'required|string',
            'location' => 'nullable|string',
            'privacy' => 'required|in:public,private',
            'invites' => 'nullable|string',          // Manual Emails
            'platform_invites' => 'nullable|array',  // Array of User IDs
            'platform_invites.*' => 'integer|exists:users,id',
        ]);

        $validated['user_id'] = auth()->id();

        // Prepare data for Repository
        $communityData = [
            'user_id' => auth()->id(),
            'name' => $validated['name'],
            'slug' => Str::slug($validated['name']),
            'description' => $validated['description'],
            'category' => $validated['category'],
            'location' => $validated['location'],
            'type' => $validated['privacy'],
        ];

        try {
            $community = $this->communityRepository->createCommunity($communityData);

            // Automatically add the creator as a member with 'admin' role
            $community->members()->attach(auth()->id(), [
                'role' => 'admin',
                'joined_at' => now(),
            ]);

            // Process Invites
            $emailList = [];

            // Process Manual Emails (Comma separated)
            if (!empty($validated['invites'])) {
                $manualEmails = array_map('trim', explode(',', $validated['invites']));
                $emailList = array_merge($emailList, array_filter($manualEmails, fn($e) => filter_var($e, FILTER_VALIDATE_EMAIL)));
            }

            // Process Platform Invites (User IDs)
            if (!empty($validated['platform_invites'])) {
                $platformEmails = User::whereIn('id', $validated['platform_invites'])
                                    ->pluck('email')
                                    ->toArray();
                $emailList = array_merge($emailList, $platformEmails);
            }

            // Unique emails only
            $finalInviteList = array_unique($emailList);

            /* * Send Invitations
            * * foreach ($finalInviteList as $email) {
            * Mail::to($email)->queue(new CommunityInvitation($community));
            * }
            */
            
           return redirect()->route('communities.index')->with('success', 'Community created successfully!');
                
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to create community: ' . $e->getMessage()])
                        ->withInput();
        }
    }

    public function edit(Community $community): View
    {
        $this->authorize('update', $community);
        
        return view('communities.edit', compact('community'));
    }

    public function update(Request $request, Community $community): RedirectResponse
    {
        $this->authorize('update', $community);

        $validated = $request->validate([
            'name' => 'required|string|max:255|unique:communities,name,' . $community->id,
            'description' => 'required|string|min:10|max:1000',
        ]);

        try {
            $this->communityRepository->updateCommunity($community, $validated);
            
            return redirect()->route('communities.show', $community)
                ->with('success', 'Community updated successfully!');
                
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to update community: ' . $e->getMessage()])
                        ->withInput();
        }
    }

    public function destroy(Community $community): RedirectResponse
    {
        $this->authorize('delete', $community);

        try {
            $this->communityRepository->deleteCommunity($community);
            
            return redirect()->route('communities.index')
                ->with('success', 'Community deleted successfully!');
                
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to delete community: ' . $e->getMessage()]);
        }
    }

    public function join(Community $community): RedirectResponse
    {
        try {
            $this->communityRepository->joinCommunity($community, auth()->user());
            
            return back()->with('success', 'You have joined the community!');
            
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to join community: ' . $e->getMessage()]);
        }
    }

    public function leave(Community $community): RedirectResponse
    {
        try {
            $this->communityRepository->leaveCommunity($community, auth()->user());
            
            return redirect()->route('communities.index')
                ->with('success', 'You have left the community.');
            
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to leave community: ' . $e->getMessage()]);
        }
    }

    public function myCommunities(Request $request): View
    {
        $filters = $request->only(['search']);
        $communities = $this->communityRepository->getUserCommunities(auth()->user(), $filters);
        
        return view('communities.my-communities', compact('communities'));
    }

    public function members(Community $community, Request $request): View
    {
        $filters = $request->only(['search', 'role']);
        $members = $this->communityRepository->getCommunityMembers($community, $filters);
        
        return view('communities.members', compact('community', 'members'));
    }

    public function updateMemberRole(Request $request, Community $community, User $user): RedirectResponse
    {
        $this->authorize('manageMembers', $community);

        $validated = $request->validate([
            'role' => 'required|in:member,moderator,admin',
        ]);

        try {
            $this->communityRepository->updateMemberRole($community, $user, $validated['role']);
            
            return back()->with('success', 'Member role updated successfully!');
            
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to update member role: ' . $e->getMessage()]);
        }
    }

    public function removeMember(Community $community, User $user): RedirectResponse
    {
        $this->authorize('manageMembers', $community);

        try {
            $this->communityRepository->leaveCommunity($community, $user);
            
            return back()->with('success', 'Member removed from community!');
            
        } catch (\Exception $e) {
            return back()->withErrors(['error' => 'Failed to remove member: ' . $e->getMessage()]);
        }
    }

    // API methods for dropdowns and frontend
    public function apiIndex(Request $request)
    {
        $filters = $request->only(['search']);
        $communities = $this->communityRepository->getAllCommunities($filters);
        
        return response()->json([
            'success' => true,
            'communities' => $communities,
        ]);
    }

    public function apiDropdown()
    {
        $communities = $this->communityRepository->getCommunitiesForDropdown();
        
        return response()->json([
            'success' => true,
            'communities' => $communities,
        ]);
    }

    public function apiJoinMultiple(Request $request)
    {
        $validated = $request->validate([
            'community_ids' => 'required|array',
            'community_ids.*' => 'exists:communities,id',
        ]);

        try {
            $user = auth()->user();
            $joined = [];
            $alreadyMember = [];

            foreach ($validated['community_ids'] as $communityId) {
                $community = Community::find($communityId);
                
                if ($this->communityRepository->userIsMember($user, $community)) {
                    $alreadyMember[] = $community->name;
                } else {
                    $this->communityRepository->joinCommunity($community, $user);
                    $joined[] = $community->name;
                }
            }

            $message = '';
            if (!empty($joined)) {
                $message .= 'Joined: ' . implode(', ', $joined) . '. ';
            }
            if (!empty($alreadyMember)) {
                $message .= 'Already member: ' . implode(', ', $alreadyMember) . '.';
            }

            return response()->json([
                'success' => true,
                'message' => trim($message),
                'joined' => $joined,
                'already_member' => $alreadyMember,
            ]);
            
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => 'Failed to join communities: ' . $e->getMessage()
            ], 422);
        }
    }

    public function networkIndex(Request $request)
    {
        $currentUser = Auth::user();
        $categories = [
            'Technology',
            'Finance',
            'Healthcare',
            'Education',
            'E-commerce',
            'Entertainment',
            'Manufacturing',
            'Consulting',
            'Telecommunications',
            'Real Estate',
            'Transportation',
            'Energy',
            'Design',
            'Product'
        ];
        $search = $request->input('search');

        $applySearch = function($query) use ($search) {
            if ($search) {
                $query->where(function($q) use ($search) {
                    // Search by Name or Nickname
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('user_name', 'like', "%{$search}%")
                      // Search by Job Details (Title, Location, Industry)
                      ->orWhereHas('activeJob', function($jobQ) use ($search) {
                          $jobQ->where('job_title', 'like', "%{$search}%")
                               ->orWhere('company_name', 'like', "%{$search}%")
                               ->orWhere('location', 'like', "%{$search}%")
                               ->orWhere('industry', 'like', "%{$search}%");
                      });
                });
            }
        };

        // Get Incoming Requests (People asking to connect with YOU)
        $incomingRequests = User::whereHas('sentConnections', function($q) use ($currentUser) {
            $q->where('recipient_id', $currentUser->id)
            ->where('status', 'pending');
        })->tap($applySearch)->with('activeJob')->get();

        // Get My Network (Connected Users + Pending OUTGOING Requests)
        // We want to see people we are connected to AND people we are waiting on.
        $networkUsers = User::where(function($q) use ($currentUser) {
            // Connected (Sent or Received)
            $q->whereHas('sentConnections', function($sub) use ($currentUser) {
                $sub->where('recipient_id', $currentUser->id)->where('status', 'connected');
            })->orWhereHas('receivedConnections', function($sub) use ($currentUser) {
                $sub->where('requester_id', $currentUser->id)->where('status', 'connected');
            })
            // PLUS: Pending Requests I SENT (Outgoing)
            ->orWhereHas('receivedConnections', function($sub) use ($currentUser) {
                $sub->where('requester_id', $currentUser->id)->where('status', 'pending');
            });
        })->tap($applySearch)->with('activeJob')->get()->map(function($user) use ($currentUser) {
            // Determine status dynamically
            $isPendingOutgoing = DB::table('connections')
                ->where('requester_id', $currentUser->id)
                ->where('recipient_id', $user->id)
                ->where('status', 'pending')
                ->exists();

            $user->connectionStatus = $isPendingOutgoing ? 'pending' : 'connected';
            return $user;
        });

        $connectedUsers = User::where(function($q) use ($currentUser) {
            // Only fetch users with 'status' = 'connected'
            $q->whereHas('sentConnections', function($sub) use ($currentUser) {
                $sub->where('recipient_id', $currentUser->id)->where('status', 'connected');
            })->orWhereHas('receivedConnections', function($sub) use ($currentUser) {
                $sub->where('requester_id', $currentUser->id)->where('status', 'connected');
            });
        })
        ->with('activeJob')
        ->get();

        // Get Discover Users
        // Exclude: Self, Connected, and Incoming Requests (we don't want to discover people who already requested us)
        $excludeIds = collect([$currentUser->id]);
        
        // Get IDs of actually connected people only (to exclude them from discover)
        $connectedIds = DB::table('connections')
            ->where(function($q) use ($currentUser) {
                $q->where('requester_id', $currentUser->id)->orWhere('recipient_id', $currentUser->id);
            })
            ->where('status', 'connected')
            ->pluck(DB::raw('CASE WHEN requester_id = '.$currentUser->id.' THEN recipient_id ELSE requester_id END'))
            ->toArray();

        $excludeIds = $excludeIds->merge($connectedIds);
        $excludeIds = $excludeIds->merge($incomingRequests->pluck('id'));

        // Get IDs of people I have ALREADY requested (Pending Outgoing)
        $pendingOutgoingIds = DB::table('connections')
            ->where('requester_id', $currentUser->id)
            ->where('status', 'pending')
            ->pluck('recipient_id')
            ->toArray();

        // Fetch Discover Users
        $discoverUsers = User::whereNotIn('id', $excludeIds)
            ->whereHas('activeJob')
            ->tap($applySearch)
            ->with('activeJob')
            ->inRandomOrder()
            ->take(12)
            ->get()
            ->map(function($user) use ($pendingOutgoingIds) {
                // Check if this user is in our pending list
                if (in_array((int)$user->id, array_map('intval', $pendingOutgoingIds))) {
                    $user->connectionStatus = 'pending';
                } else {
                    $user->connectionStatus = 'none';
                }
                return $user;
            });
        
        // Communities
        $myCommunities = $currentUser->communities()->withCount('members')->orderBy('name')->get()->map(function($c) { $c->isJoined = true; return $c; });
        $discoverCommunities = Community::whereNotIn('id', $myCommunities->pluck('id'))->withCount('members')->orderBy('members_count', 'desc')->take(6)->get()->map(function($c) { $c->isJoined = false; return $c; });

        // Suggested People (Take from Discover)
        $suggestedPeople = $discoverUsers->take(3);

        return view('dashboard.community.index', compact(
            'incomingRequests',
            'networkUsers',
            'discoverUsers',
            'myCommunities',
            'discoverCommunities',
            'suggestedPeople',
            'categories',
            'connectedUsers',
        ));
    }

    // ===========================
    // ACTIONS
    // ===========================

    public function connect(User $user)
    {
        $exists = DB::table('connections')->where(function($q) use ($user) {
            $q->where('requester_id', Auth::id())->where('recipient_id', $user->id);
        })->orWhere(function($q) use ($user) {
            $q->where('requester_id', $user->id)->where('recipient_id', Auth::id());
        })->exists();

        if (!$exists) {
            DB::table('connections')->insert([
                'requester_id' => Auth::id(),
                'recipient_id' => $user->id,
                'status' => 'pending',
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }

        if (request()->wantsJson()) {
            return response()->json(['status' => 'success', 'message' => 'Request sent']);
        }

        return back()->with('success', 'Connection request sent to @' . $user->user_name);
    }

    public function accept($userId)
    {
        DB::table('connections')
            ->where('requester_id', $userId)
            ->where('recipient_id', Auth::id())
            ->update(['status' => 'connected', 'updated_at' => now()]);

        if (request()->wantsJson()) {
            return response()->json(['status' => 'success']);
        }

        return back()->with('success', 'Connection accepted!');
    }

    public function ignore($userId)
    {
        DB::table('connections')
            ->where('requester_id', $userId)
            ->where('recipient_id', Auth::id())
            ->update(['status' => 'declined', 'updated_at' => now()]);

        if (request()->wantsJson()) {
            return response()->json(['status' => 'success']);
        }
        return back()->with('info', 'Request ignored.');
    }
}