<?php

namespace App\Http\Controllers\Partnership;

use App\Http\Controllers\Controller;
use App\Models\RForumThread;
use App\Models\RForumReply;
use App\Models\RForumAttachment;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

/**
 * Controller: RForumController
 *
 * Handles the networking forum for partners and mentors.
 * Supports file attachments, read/unread tracking, and right-click context actions.
 */
class RForumController extends Controller
{
    /** Max file size in KB */
    const MAX_FILE_SIZE_KB = 10240; // 10 MB

    /** Allowed MIME types */
    const ALLOWED_MIMES = [
        'image/jpeg', 'image/png', 'image/gif', 'image/webp',
        'application/pdf',
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'application/vnd.ms-excel',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    ];

    /**
     * Display forum thread listing.
     */
    public function index(Request $request): View
    {
        $this->checkForumAccess();

        $query = RForumThread::approved()
                           ->with(['user', 'partner', 'lastReplyUser'])
                           ->whereIn('visibility', $this->getVisibleVisibilities())
                           ->orderByDesc('is_pinned')
                           ->orderByDesc('last_reply_at');

        if ($request->filled('category')) {
            $query->where('category', $request->category);
        }

        if ($request->filled('q')) {
            $search = $request->q;
            $query->where(function ($q) use ($search) {
                $q->where('title', 'LIKE', "%{$search}%")
                  ->orWhere('content', 'LIKE', "%{$search}%");
            });
        }

        $threads = $query->paginate(20);

        // Attach read status for current user
        $userId = auth()->id();
        $threadIds = $threads->pluck('id');
        $readThreadIds = DB::table('r_forum_thread_reads')
            ->where('user_id', $userId)
            ->where('is_read', true)
            ->whereIn('thread_id', $threadIds)
            ->pluck('thread_id')
            ->toArray();

        $threads->each(function ($thread) use ($readThreadIds) {
            $thread->is_read_by_user = in_array($thread->id, $readThreadIds);
        });

        $categories = [
            'general'        => 'General Discussion',
            'collaboration'  => 'Collaboration',
            'resources'      => 'Resources',
            'events'         => 'Events',
            'announcements'  => 'Announcements',
            'questions'      => 'Questions & Answers',
            'best_practices' => 'Best Practices',
            'opportunities'  => 'Opportunities',
        ];

        return view('forum.index', [
            'threads'    => $threads,
            'categories' => $categories,
            'filters'    => $request->only(['category', 'q']),
        ]);
    }

    /**
     * Real-time search (AJAX).
     */
    public function search(Request $request): JsonResponse
    {
        $this->checkForumAccess();

        $q = $request->get('q', '');
        $category = $request->get('category', '');

        $query = RForumThread::approved()
            ->with('user')
            ->whereIn('visibility', $this->getVisibleVisibilities())
            ->orderByDesc('is_pinned')
            ->orderByDesc('last_reply_at');

        if (!empty($q)) {
            $query->where(function ($sq) use ($q) {
                $sq->where('title', 'LIKE', "%{$q}%")
                   ->orWhere('content', 'LIKE', "%{$q}%");
            });
        }

        if (!empty($category)) {
            $query->where('category', $category);
        }

        $threads = $query->limit(30)->get();

        return response()->json([
            'success' => true,
            'threads' => $threads->map(fn($t) => [
                'id'           => $t->id,
                'title'        => $t->title,
                'category'     => $t->category_label,
                'replies'      => $t->replies_count,
                'views'        => $t->views_count,
                'is_pinned'    => $t->is_pinned,
                'is_locked'    => $t->is_locked,
                'author'       => $t->user->name,
                'last_activity'=> $t->last_reply_at ? $t->last_reply_at->diffForHumans() : $t->created_at->diffForHumans(),
                'url'          => route('partners.forum.show', $t),
            ]),
        ]);
    }

    /**
     * Display single thread.
     */
    public function show(RForumThread $thread): View
    {
        $this->checkForumAccess();

        if (!$this->canViewThread($thread)) {
            abort(403, 'You do not have access to this thread.');
        }

        $thread->incrementViews();

        // Mark as read for current user
        DB::table('r_forum_thread_reads')->updateOrInsert(
            ['thread_id' => $thread->id, 'user_id' => auth()->id()],
            ['is_read' => true, 'read_at' => now(), 'updated_at' => now(), 'created_at' => now()]
        );

        $thread->load([
            'user',
            'partner',
            'attachments',
            'replies' => function ($q) {
                $q->published()->root()->orderBy('created_at');
            },
            'replies.user',
            'replies.attachments',
            'replies.replies.user',
            'replies.replies.attachments',
        ]);

        return view('forum.show', [
            'thread' => $thread,
        ]);
    }

    /**
     * Show form for creating thread.
     */
    public function create(): View
    {
        $this->checkForumAccess();
        return view('forum.create');
    }

    /**
     * Store new thread.
     */
    public function store(Request $request): mixed
    {
        $this->checkForumAccess();

        $validated = $request->validate([
            'title'      => 'required|string|max:191|min:5',
            'content'    => 'required|string|min:10|max:50000',
            'category'   => 'required|string|max:50',
            'visibility' => 'sometimes|in:public,partners_only,mentors_only,private',
            'tags_input' => 'nullable|string|max:500',
            'attachments'   => 'nullable|array|max:5',
            'attachments.*' => [
                'file',
                'max:' . self::MAX_FILE_SIZE_KB,
                'mimes:jpeg,jpg,png,gif,webp,pdf,doc,docx,xls,xlsx',
            ],
        ]);

        try {
            // Parse tags
            $tags = [];
            if (!empty($validated['tags_input'])) {
                $tags = array_values(array_filter(
                    array_map('trim', explode(',', $validated['tags_input']))
                ));
                $tags = array_slice($tags, 0, 5);
            }

            $thread = RForumThread::create([
                'user_id'    => auth()->id(),
                'title'      => $validated['title'],
                'slug'       => RForumThread::generateSlug($validated['title']),
                'content'    => $validated['content'],
                'category'   => $validated['category'],
                'visibility' => $validated['visibility'] ?? 'public',
                'tags'       => $tags,
                'status'     => RForumThread::STATUS_OPEN,
                'is_approved'=> true,
            ]);

            // Handle attachments
            if ($request->hasFile('attachments')) {
                $this->storeAttachments($request->file('attachments'), $thread);
            }

            return redirect()
                ->route('partners.forum.show', $thread)
                ->with('success', 'Thread created successfully!');

        } catch (\Exception $e) {
            return back()->withInput()->with('error', 'Failed to create thread: ' . $e->getMessage());
        }
    }

    /**
     * Store reply to thread.
     */
    public function reply(Request $request, RForumThread $thread): mixed
    {
        $this->checkForumAccess();

        if ($thread->isLocked()) {
            return back()->with('error', 'This thread is locked for new replies.');
        }

        $validated = $request->validate([
            'content'       => 'required|string|min:5|max:20000',
            'parent_id'     => 'nullable|exists:r_forum_replies,id',
            'attachments'   => 'nullable|array|max:5',
            'attachments.*' => [
                'file',
                'max:' . self::MAX_FILE_SIZE_KB,
                'mimes:jpeg,jpg,png,gif,webp,pdf,doc,docx,xls,xlsx',
            ],
        ]);

        try {
            $reply = RForumReply::create([
                'thread_id'  => $thread->id,
                'user_id'    => auth()->id(),
                'parent_id'  => $validated['parent_id'] ?? null,
                'content'    => $validated['content'],
                'status'     => RForumReply::STATUS_PUBLISHED,
                'is_approved'=> true,
                'ip_address' => $request->ip(),
            ]);

            if ($request->hasFile('attachments')) {
                $this->storeAttachments($request->file('attachments'), $reply);
            }

            $thread->updateReplyStats();

            return redirect()
                ->route('partners.forum.show', $thread)
                ->with('success', 'Reply posted successfully!');

        } catch (\Exception $e) {
            return back()->withInput()->with('error', 'Failed to post reply: ' . $e->getMessage());
        }
    }

    /**
     * Edit reply.
     */
    public function editReply(RForumReply $reply): View
    {
        abort_unless(
            $reply->isAuthor(auth()->id()) || auth()->user()->can('moderate forum'),
            403
        );

        $reply->load('attachments');

        return view('forum.edit-reply', [
            'reply'  => $reply,
            'thread' => $reply->thread,
        ]);
    }

    /**
     * Update reply.
     */
    public function updateReply(Request $request, RForumReply $reply): mixed
    {
        abort_unless(
            $reply->isAuthor(auth()->id()) || auth()->user()->can('moderate forum'),
            403
        );

        $validated = $request->validate([
            'content'            => 'required|string|min:5|max:20000',
            'attachments'        => 'nullable|array|max:5',
            'attachments.*'      => [
                'file',
                'max:' . self::MAX_FILE_SIZE_KB,
                'mimes:jpeg,jpg,png,gif,webp,pdf,doc,docx,xls,xlsx',
            ],
            'remove_attachments' => 'nullable|array',
            'remove_attachments.*' => 'integer|exists:r_forum_attachments,id',
        ]);

        try {
            $reply->update(['content' => $validated['content']]);
            $reply->markAsEdited(auth()->id());

            // Remove selected attachments
            if (!empty($validated['remove_attachments'])) {
                $toRemove = RForumAttachment::whereIn('id', $validated['remove_attachments'])
                    ->where('attachable_type', 'App\\Models\\RForumReply')
                    ->where('attachable_id', $reply->id)
                    ->get();
                foreach ($toRemove as $att) {
                    Storage::disk($att->disk)->delete($att->path);
                    $att->delete();
                }
            }

            if ($request->hasFile('attachments')) {
                $this->storeAttachments($request->file('attachments'), $reply);
            }

            return redirect()
                ->route('partners.forum.show', $reply->thread)
                ->with('success', 'Reply updated successfully!');

        } catch (\Exception $e) {
            return back()->withInput()->with('error', 'Failed to update reply: ' . $e->getMessage());
        }
    }

    /**
     * Delete reply.
     */
    public function destroyReply(RForumReply $reply): mixed
    {
        abort_unless(
            $reply->isAuthor(auth()->id()) || auth()->user()->can('moderate forum'),
            403
        );

        $thread = $reply->thread;

        // Delete attachments
        foreach ($reply->attachments as $att) {
            Storage::disk($att->disk)->delete($att->path);
            $att->delete();
        }

        $reply->delete();
        $thread->updateReplyStats();

        return redirect()
            ->route('partners.forum.show', $thread)
            ->with('success', 'Reply deleted.');
    }

    /**
     * Mark reply as best answer.
     */
    public function markBestAnswer(RForumReply $reply): JsonResponse
    {
        abort_unless(
            $reply->thread->isAuthor(auth()->id()) || auth()->user()->can('moderate forum'),
            403
        );

        $reply->markAsBest(auth()->id());

        return response()->json(['success' => true, 'message' => 'Marked as best answer!']);
    }

    /**
     * Lock/unlock thread.
     */
    public function toggleLock(RForumThread $thread): JsonResponse
    {
        abort_unless(auth()->user()->can('moderate forum'), 403);

        if ($thread->is_locked) {
            $thread->unlock();
            $message = 'Thread unlocked.';
        } else {
            $thread->lock();
            $message = 'Thread locked.';
        }

        return response()->json([
            'success'   => true,
            'is_locked' => $thread->fresh()->is_locked,
            'message'   => $message,
        ]);
    }

    /**
     * Pin/unpin thread.
     */
    public function togglePin(RForumThread $thread): JsonResponse
    {
        abort_unless(auth()->user()->can('moderate forum'), 403);

        if ($thread->is_pinned) {
            $thread->unpin();
            $message = 'Thread unpinned.';
        } else {
            $thread->pin();
            $message = 'Thread pinned.';
        }

        return response()->json([
            'success'   => true,
            'is_pinned' => $thread->fresh()->is_pinned,
            'message'   => $message,
        ]);
    }

    /**
     * Mark thread as read (AJAX).
     */
    public function markRead(RForumThread $thread): JsonResponse
    {
        $this->checkForumAccess();

        DB::table('r_forum_thread_reads')->updateOrInsert(
            ['thread_id' => $thread->id, 'user_id' => auth()->id()],
            ['is_read' => true, 'read_at' => now(), 'updated_at' => now(), 'created_at' => now()]
        );

        return response()->json(['success' => true, 'message' => 'Marked as read.']);
    }

    /**
     * Mark thread as unread (AJAX).
     */
    public function markUnread(RForumThread $thread): JsonResponse
    {
        $this->checkForumAccess();

        DB::table('r_forum_thread_reads')->updateOrInsert(
            ['thread_id' => $thread->id, 'user_id' => auth()->id()],
            ['is_read' => false, 'read_at' => null, 'updated_at' => now(), 'created_at' => now()]
        );

        return response()->json(['success' => true, 'message' => 'Marked as unread.']);
    }

    /**
     * Mark reply as helpful.
     */
    public function markHelpful(RForumReply $reply): JsonResponse
    {
        $reply->markHelpful();

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

    /**
     * Delete thread.
     */
    public function destroy(RForumThread $thread): mixed
    {
        abort_unless(
            $thread->isAuthor(auth()->id()) || auth()->user()->can('moderate forum'),
            403
        );

        // Delete all attachments
        $thread->load('attachments');
        foreach ($thread->attachments as $att) {
            Storage::disk($att->disk)->delete($att->path);
            $att->delete();
        }

        $thread->delete();

        return redirect()
            ->route('partners.forum.index')
            ->with('success', 'Thread deleted.');
    }

    /**
     * Download attachment.
     */
    public function downloadAttachment(RForumAttachment $attachment): mixed
    {
        $this->checkForumAccess();

        if (!Storage::disk($attachment->disk)->exists($attachment->path)) {
            abort(404, 'File not found.');
        }

        return Storage::disk($attachment->disk)->download($attachment->path, $attachment->original_name);
    }

    /**
     * Delete attachment (AJAX).
     */
    public function deleteAttachment(RForumAttachment $attachment): JsonResponse
    {
        $user = auth()->user();
        abort_unless(
            $attachment->user_id === $user->id || $user->can('moderate forum'),
            403
        );

        Storage::disk($attachment->disk)->delete($attachment->path);
        $attachment->delete();

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

    // ─────────────────────────────────────────────────────────────────────────
    // Helpers
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Store uploaded files as attachments on a model.
     */
    protected function storeAttachments(array $files, $model): void
    {
        foreach ($files as $file) {
            if (!$file->isValid()) continue;

            $mime      = $file->getMimeType();
            $ext       = $file->getClientOriginalExtension();
            $original  = $file->getClientOriginalName();
            $stored    = Str::uuid() . '.' . $ext;
            $path      = $file->storeAs('forum/attachments', $stored, 'public');

            $model->attachments()->create([
                'user_id'       => auth()->id(),
                'original_name' => $original,
                'stored_name'   => $stored,
                'path'          => $path,
                'disk'          => 'public',
                'mime_type'     => $mime,
                'size'          => $file->getSize(),
                'extension'     => strtolower($ext),
                'type'          => RForumAttachment::resolveType($mime),
            ]);
        }
    }

    /**
     * Check if user has forum access.
     */
    protected function checkForumAccess(): void
    {
        $user = auth()->user();

        $hasAccess = $user->hasAnyRole([
            'Super Manager',
            'Manager',
            'Partners',
            'Mentor',
            'Health Marketor',
        ]);

        abort_unless($hasAccess, 403, 'You do not have access to the forum.');
    }

    /**
     * Get visible visibilities based on user role.
     */
    protected function getVisibleVisibilities(): array
    {
        $user = auth()->user();

        $visibilities = ['public'];

        if ($user->hasRole('Partners')) {
            $visibilities[] = 'partners_only';
        }

        if ($user->hasRole('Mentor')) {
            $visibilities[] = 'mentors_only';
        }

        if ($user->hasAnyRole(['Super Manager', 'Manager'])) {
            $visibilities = ['public', 'partners_only', 'mentors_only', 'private'];
        }

        return $visibilities;
    }

    /**
     * Check if user can view thread.
     */
    protected function canViewThread(RForumThread $thread): bool
    {
        $user = auth()->user();

        if ($thread->visibility === 'public') return true;
        if ($thread->visibility === 'partners_only' && $user->hasRole('Partners')) return true;
        if ($thread->visibility === 'mentors_only' && $user->hasRole('Mentor')) return true;
        if ($user->hasAnyRole(['Super Manager', 'Manager'])) return true;

        return false;
    }
}
