<?php

namespace App\Http\Controllers;

use App\Models\ForumBoard;
use App\Models\ForumCategory;
use App\Models\ForumPost;
use App\Models\ForumReaction;
use App\Models\ForumThread;
use App\Helpers\ActivityLogger;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use App\Notifications\ThreadReactionNotification;
use App\Notifications\ThreadReplyNotification;
use App\Notifications\PostReactionNotification;

class ForumController extends Controller
{
    /**
     * Constructor - apply middleware
     */
    public function __construct()
    {
        $this->middleware('auth')->except(['index', 'board', 'thread']);
    }
    
    /**
     * Display forum index with categories and boards (filtered by access)
     */
    public function index()
    {
        $categories = ForumCategory::with(['accessibleBoards' => function ($query) {
            $query->where('is_active', true)->orderBy('order');
        }])
        ->where('is_active', true)
        ->accessible()
        ->orderBy('order')
        ->get()
        ->filter(function ($category) {
            // Only show categories that have accessible boards or are accessible themselves
            return $category->canAccess() && $category->accessibleBoards->count() > 0;
        });
        
        return view('forum.index', compact('categories'));
    }
    
    /**
     * Display board with threads (with access control)
     */
    public function board(string $slug)
    {
        $board = ForumBoard::where('slug', $slug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            if (Auth::guest()) {
                return redirect()->route('login.steam')
                    ->with('error', 'You need to login to access this board.');
            }
            abort(403, 'You do not have permission to access this board.');
        }
            
        $threads = $board->threads()
            ->with('user')
            ->withCount('posts')
            ->orderByDesc('is_pinned')
            ->orderByDesc('last_activity_at')
            ->paginate(20);
            
        return view('forum.board', compact('board', 'threads'));
    }
    
    /**
     * Show form to create a new thread (with access control)
     */
    public function createThread(string $boardSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to create threads in this board.');
        }
            
        return view('forum.create_thread', compact('board'));
    }
    
    /**
     * Store a new thread (with access control)
     */
    public function storeThread(Request $request, string $boardSlug)
    {
        $max_chars = config_value('forum_max_characters', 10000);
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to create threads in this board.');
        }
        
        $validator = Validator::make($request->all(), [
            'title' => 'required|min:3|max:255',
            'content' => 'required|min:10|max:' . $max_chars,
        ]);
        
        if ($validator->fails()) {
            return redirect()
                ->route('forum.create-thread', $board->slug)
                ->withErrors($validator)
                ->withInput();
        }
        
        $thread = new ForumThread();
        $thread->board_id = $board->id;
        $thread->user_id = Auth::id();
        $thread->title = $request->title;
        $thread->slug = Str::slug($request->title) . '-' . Str::random(6);
        $thread->content = $request->content;
        $thread->last_activity_at = now();
        $thread->save();

        Auth::user()->unlock(new \App\Achievements\CreatedFirstThread());
        Auth::user()->addProgress(new \App\Achievements\Created5Threads(), 1);

        ActivityLogger::logActivity(Auth::user(), 'started thread', ['thread_name' => $thread->title, 'board_name' => $thread->board->name]);

        return redirect()->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Thread created successfully!');
    }
    
    /**
     * Show a thread with its posts (with access control)
     */
    public function thread(string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            if (Auth::guest()) {
                return redirect()->route('login.steam')
                    ->with('error', 'You need to login to access this thread.');
            }
            abort(403, 'You do not have permission to access this thread.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        $thread->incrementViewCount();
        
        $posts = $thread->posts()
            ->with('user', 'reactions')
            ->paginate(20);
            
        return view('forum.thread', compact('board', 'thread', 'posts'));
    }
    
    /**
     * Store a new post (reply) in a thread (with access control)
     */
    public function storePost(Request $request, string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to reply in this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        if ($thread->is_locked) {
            return redirect()
                ->route('forum.thread', [$board->slug, $thread->slug])
                ->with('error', 'This thread is locked and cannot be replied to.');
        }

        $post_count = $thread->posts()->count();
        $max_replies = config_value('forum_max_replies', 1000);

        if ($post_count >= $max_replies) {
            return redirect()
                ->route('forum.thread', [$board->slug, $thread->slug])
                ->with('error', "This thread has reached the maximum number of allowed replies ({$max_replies}).");
        }

        $validator = Validator::make($request->all(), [
            'content' => 'required|min:2',
        ]);
        
        if ($validator->fails()) {
            return redirect()
                ->route('forum.thread', [$board->slug, $thread->slug])
                ->withErrors($validator)
                ->withInput();
        }

        $post = new ForumPost();
        $post->thread_id = $thread->id;
        $post->user_id = Auth::id();
        $post->content = $request->content;
        $post->save();

        $thread->last_activity_at = now();
        $thread->save();

        Auth::user()->unlock(new \App\Achievements\PostedReply());
        Auth::user()->addProgress(new \App\Achievements\Posted5Replies(), 1);

        ActivityLogger::logActivity(Auth::user(), 'replied to thread', ['thread_name' => $thread->title]);

        // Send notification to thread author (if not replying to own thread)
        if ($thread->user_id !== Auth::id()) {
            $thread->user->notify(new ThreadReplyNotification(Auth::user(), $thread, $post));
        }
        
        return redirect()
            ->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Reply posted successfully!');
    }

    /**
     * Toggle a reaction on a post
     */
    public function toggleReaction(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'post_id' => 'required|exists:forum_posts,id',
            'type' => ['required', Rule::in(array_keys(ForumReaction::getTypes()))],
        ]);
        
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid reaction request'
            ]);
        }
        
        $post = ForumPost::with('user', 'thread.board')->findOrFail($request->post_id);
        $userId = Auth::id();
        $type = $request->type;

        // Check if user can access the board this post belongs to
        if (!$post->thread->board->canAccess()) {
            return response()->json([
                'success' => false,
                'message' => 'You do not have permission to react to posts in this board'
            ]);
        }
        
        $existingReaction = ForumReaction::where('user_id', $userId)
            ->where('reactable_id', $post->id)
            ->where('reactable_type', get_class($post))
            ->where('type', $type)
            ->first();
            
        if ($existingReaction) {
            // Remove reaction if it exists
            $existingReaction->delete();
            $action = 'removed';
        } else {
            // Add new reaction
            ForumReaction::create([
                'user_id' => $userId,
                'reactable_id' => $post->id,
                'reactable_type' => get_class($post),
                'type' => $type
            ]);
            $action = 'added';
            
            // Send notification to post author (if not reacting to own post)
            if ($post->user_id !== $userId) {
                $post->user->notify(new PostReactionNotification(Auth::user(), $post, $type));
            }
        }
        
        // Get updated count
        $newCount = $post->getReactionCount($type);
        
        return response()->json([
            'success' => true,
            'action' => $action,
            'type' => $type,
            'count' => $newCount
        ]);
    }
    
    /**
     * Toggle a reaction on a thread
     */
    public function toggleThreadReaction(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'thread_id' => 'required|exists:forum_threads,id',
            'type' => ['required', Rule::in(array_keys(ForumReaction::getTypes()))],
        ]);
        
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid reaction request'
            ]);
        }
        
        $thread = ForumThread::with('user', 'board')->findOrFail($request->thread_id);
        $userId = Auth::id();
        $type = $request->type;

        // Check if user can access the board this thread belongs to
        if (!$thread->board->canAccess()) {
            return response()->json([
                'success' => false,
                'message' => 'You do not have permission to react to threads in this board'
            ]);
        }
        
        $existingReaction = ForumReaction::where('user_id', $userId)
            ->where('reactable_id', $thread->id)
            ->where('reactable_type', get_class($thread))
            ->where('type', $type)
            ->first();
            
        if ($existingReaction) {
            // Remove reaction if it exists
            $existingReaction->delete();
            $action = 'removed';
        } else {
            // Add new reaction
            ForumReaction::create([
                'user_id' => $userId,
                'reactable_id' => $thread->id,
                'reactable_type' => get_class($thread),
                'type' => $type
            ]);
            $action = 'added';
            
            // Send notification to thread author (if not reacting to own thread)
            if ($thread->user_id !== $userId) {
                $thread->user->notify(new ThreadReactionNotification(Auth::user(), $thread, $type));
            }
        }
        
        // Get updated count for thread reactions
        $newCount = $thread->reactions()->where('type', $type)->count();
        
        return response()->json([
            'success' => true,
            'action' => $action,
            'type' => $type,
            'count' => $newCount
        ]);
    }
    
    /**
     * Show form to edit a thread (with access control)
     */
    public function editThread(string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        // Check if user is authorized to edit the thread
        if (!(Auth::user()->can('moderate forums') || Auth::id() === $thread->user_id)) {
            abort(403, 'Unauthorized action.');
        }
        
        return view('forum.edit_thread', compact('board', 'thread'));
    }
    
    /**
     * Update a thread (with access control)
     */
    public function updateThread(Request $request, string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        // Check if user is authorized to edit the thread
        if (!(Auth::user()->can('moderate forums') || Auth::id() === $thread->user_id)) {
            abort(403, 'Unauthorized action.');
        }
        
        $validator = Validator::make($request->all(), [
            'title' => 'required|min:3|max:255',
            'content' => 'required|min:10',
        ]);
        
        if ($validator->fails()) {
            return redirect()
                ->route('forum.edit-thread', [$board->slug, $thread->slug])
                ->withErrors($validator)
                ->withInput();
        }
        
        // Only update slug if title has changed and user is a moderator
        if ($request->title !== $thread->title && Auth::user()->can('moderate forums')) {
            $thread->slug = Str::slug($request->title) . '-' . Str::random(6);
        }
        
        $thread->title = $request->title;
        $thread->content = $request->content;
        
        // Handle moderation actions if user has permission
        if (Auth::user()->can('moderate forums')) {
            $thread->is_pinned = $request->has('is_pinned');
            $thread->is_locked = $request->has('is_locked');
        }
        
        $thread->save();
        
        return redirect()
            ->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Thread updated successfully!');
    }
    
    /**
     * Delete a thread (with access control)
     */
    public function deleteThread(string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        // Only moderators can delete threads
        if (!Auth::user()->can('moderate forums')) {
            abort(403, 'Unauthorized action.');
        }
        
        $threadTitle = $thread->title;
        
        // Delete thread along with its posts and reactions
        $thread->delete();
        
        ActivityLogger::logActivity(Auth::user(), 'deleted thread', ['thread_name' => $threadTitle, 'board_name' => $board->name]);
        
        return redirect()
            ->route('forum.board', $board->slug)
            ->with('success', 'Thread deleted successfully!');
    }
    
    /**
     * Toggle thread lock status (with access control)
     */
    public function toggleLockThread(string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        // Only moderators can lock/unlock threads
        if (!Auth::user()->can('moderate forums')) {
            abort(403, 'Unauthorized action.');
        }
        
        $thread->is_locked = !$thread->is_locked;
        $thread->save();
        
        $action = $thread->is_locked ? 'locked' : 'unlocked';
        ActivityLogger::logActivity(Auth::user(), $action . ' thread', ['thread_name' => $thread->title]);
        
        return redirect()
            ->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Thread ' . $action . ' successfully!');
    }
    
    /**
     * Toggle thread pin status (with access control)
     */
    public function togglePinThread(string $boardSlug, string $threadSlug)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        // Only moderators can pin/unpin threads
        if (!Auth::user()->can('moderate forums')) {
            abort(403, 'Unauthorized action.');
        }
        
        $thread->is_pinned = !$thread->is_pinned;
        $thread->save();
        
        $action = $thread->is_pinned ? 'pinned' : 'unpinned';
        ActivityLogger::logActivity(Auth::user(), $action . ' thread', ['thread_name' => $thread->title]);
        
        return redirect()
            ->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Thread ' . $action . ' successfully!');
    }
    
    /**
     * Edit a post (reply) (with access control)
     */
    public function editPost(string $boardSlug, string $threadSlug, int $postId)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        $post = ForumPost::where('id', $postId)
            ->where('thread_id', $thread->id)
            ->firstOrFail();
            
        // Check if user is authorized to edit the post
        if (!(Auth::user()->can('moderate forums') || Auth::id() === $post->user_id)) {
            abort(403, 'Unauthorized action.');
        }
        
        return view('forum.edit_post', compact('board', 'thread', 'post'));
    }
    
    /**
     * Update a post (reply) (with access control)
     */
    public function updatePost(Request $request, string $boardSlug, string $threadSlug, int $postId)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        $post = ForumPost::where('id', $postId)
            ->where('thread_id', $thread->id)
            ->firstOrFail();
            
        // Check if user is authorized to edit the post
        if (!(Auth::user()->can('moderate forums') || Auth::id() === $post->user_id)) {
            abort(403, 'Unauthorized action.');
        }
        
        $validator = Validator::make($request->all(), [
            'content' => 'required|min:2',
        ]);
        
        if ($validator->fails()) {
            return redirect()
                ->route('forum.edit-post', [$board->slug, $thread->slug, $post->id])
                ->withErrors($validator)
                ->withInput();
        }
        
        $post->content = $request->content;
        $post->is_edited = true;
        $post->edited_at = now();
        $post->save();
        
        ActivityLogger::logActivity(Auth::user(), 'edited post', ['thread_name' => $thread->title]);
        
        return redirect()
            ->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Post updated successfully!');
    }
    
    /**
     * Delete a post (reply) (with access control)
     */
    public function deletePost(string $boardSlug, string $threadSlug, int $postId)
    {
        $board = ForumBoard::where('slug', $boardSlug)
            ->where('is_active', true)
            ->firstOrFail();
        
        // Check if user can access this board
        if (!$board->canAccess()) {
            abort(403, 'You do not have permission to access this board.');
        }
            
        $thread = ForumThread::where('slug', $threadSlug)
            ->where('board_id', $board->id)
            ->firstOrFail();
            
        $post = ForumPost::where('id', $postId)
            ->where('thread_id', $thread->id)
            ->firstOrFail();
            
        // Only moderators can delete posts
        if (!Auth::user()->can('moderate forums')) {
            abort(403, 'Unauthorized action.');
        }
        
        // Delete the post
        $post->delete();
        
        ActivityLogger::logActivity(Auth::user(), 'deleted post', ['thread_name' => $thread->title]);
        
        return redirect()
            ->route('forum.thread', [$board->slug, $thread->slug])
            ->with('success', 'Post deleted successfully!');
    }
}