<?php

namespace App\Http\Controllers\Forum;

use App\Http\Controllers\Controller;
use App\Services\Activity\UserActivityService;
use App\Models\ForumCategory;
use App\Models\ForumPost;
use App\Models\ForumPostReport;
use App\Models\ForumThread;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;

class ForumController extends Controller
{
    public function index()
    {
        $categories = Cache::remember('forum:index:categories:v1', now()->addMinutes(5), function () {
            return ForumCategory::query()
                ->select(['id', 'name', 'slug', 'parent_id', 'position'])
                ->roots()
                ->ordered()
                ->withForumStats()
                ->get()
                ->map(function (ForumCategory $category) {
                    return [
                        'id' => $category->id,
                        'name' => $category->name,
                        'slug' => $category->slug,
                        'thread_count' => (int) ($category->thread_count ?? 0),
                        'post_count' => (int) ($category->post_count ?? 0),
                        'last_activity_at' => $category->lastThread?->last_post_at ?? $category->lastThread?->updated_at,
                        'preview_image' => $category->preview_image,
                    ];
                });
        });

        $data = [
            'categories' => $categories,
            'page_title' => 'Forum',
            'page_meta_description' => 'Skinbase forum discussions.',
            'page_meta_keywords' => 'forum, discussions, topics, skinbase',
        ];

        return view('forum.index', $data);
    }

    public function showCategory(Request $request, ForumCategory $category)
    {
        $subtopics = ForumThread::query()
            ->where('category_id', $category->id)
            ->withCount('posts')
            ->with('user:id,name')
            ->orderByDesc('is_pinned')
            ->orderByDesc('last_post_at')
            ->orderByDesc('id')
            ->paginate(50)
            ->withQueryString();

        $subtopics->getCollection()->transform(function (ForumThread $item) {
            return (object) [
                'topic_id' => $item->id,
                'topic' => $item->title,
                'discuss' => $item->content,
                'post_date' => $item->created_at,
                'last_update' => $item->last_post_at ?? $item->created_at,
                'uname' => $item->user?->name,
                'num_posts' => (int) ($item->posts_count ?? 0),
                'is_pinned' => (bool) $item->is_pinned,
            ];
        });

        $topic = (object) [
            'topic_id' => $category->id,
            'topic' => $category->name,
            'discuss' => null,
        ];

        return view('forum.community.topic', [
            'type' => 'subtopics',
            'topic' => $topic,
            'subtopics' => $subtopics,
            'category' => $category,
            'page_title' => $category->name,
            'page_meta_description' => 'Forum section: ' . $category->name,
            'page_meta_keywords' => 'forum, section, skinbase',
        ]);
    }

    public function showThread(Request $request, ForumThread $thread, ?string $slug = null)
    {
        if (! empty($thread->slug) && $slug !== $thread->slug) {
            return redirect()->route('forum.thread.show', ['thread' => $thread->id, 'slug' => $thread->slug], 301);
        }

        $thread->loadMissing([
            'category:id,name,slug',
            'user:id,name',
            'user.profile:user_id,avatar_hash',
        ]);

        $threadMeta = Cache::remember(
            'forum:thread:meta:v1:' . $thread->id . ':' . ($thread->updated_at?->timestamp ?? 0),
            now()->addMinutes(5),
            fn () => [
                'category' => $thread->category,
                'author' => $thread->user,
            ]
        );

        $sort = strtolower((string) $request->query('sort', 'asc')) === 'desc' ? 'desc' : 'asc';

        $opPost = ForumPost::query()
            ->where('thread_id', $thread->id)
            ->with([
                'user:id,name',
                'user.profile:user_id,avatar_hash',
                'attachments:id,post_id,file_path,file_size,mime_type,width,height',
            ])
            ->orderBy('created_at', 'asc')
            ->orderBy('id', 'asc')
            ->first();

        $posts = ForumPost::query()
            ->where('thread_id', $thread->id)
            ->when($opPost, fn ($query) => $query->where('id', '!=', $opPost->id))
            ->with([
                'user:id,name',
                'user.profile:user_id,avatar_hash',
                'attachments:id,post_id,file_path,file_size,mime_type,width,height',
            ])
            ->orderBy('created_at', $sort)
            ->paginate(50)
            ->withQueryString();

        $replyCount = max((int) ForumPost::query()->where('thread_id', $thread->id)->count() - 1, 0);

        $attachments = collect($opPost?->attachments ?? [])
            ->merge($posts->getCollection()->flatMap(fn (ForumPost $post) => $post->attachments ?? []))
            ->values();

        $quotedPost = null;
        $quotePostId = (int) $request->query('quote', 0);

        if ($quotePostId > 0) {
            $quotedPost = ForumPost::query()
                ->where('thread_id', $thread->id)
                ->with('user:id,name')
                ->find($quotePostId);
        }

        $replyPrefill = old('content');

        if ($replyPrefill === null && $quotedPost) {
            $quotedAuthor = (string) ($quotedPost->user?->name ?? 'Anonymous');
            $quoteText = trim(strip_tags((string) $quotedPost->content));
            $quoteText = preg_replace('/\s+/', ' ', $quoteText) ?? $quoteText;
            $quoteSnippet = Str::limit($quoteText, 300);

            $replyPrefill = '[quote=' . $quotedAuthor . ']'
                . $quoteSnippet
                . '[/quote]'
                . "\n\n";
        }

        return view('forum.thread.show', [
            'thread' => $thread,
            'category' => $threadMeta['category'] ?? $thread->category,
            'author' => $threadMeta['author'] ?? $thread->user,
            'opPost' => $opPost,
            'posts' => $posts,
            'attachments' => $attachments,
            'reply_count' => $replyCount,
            'quoted_post' => $quotedPost,
            'reply_prefill' => $replyPrefill,
            'sort' => $sort,
            'page_title' => $thread->title,
            'page_meta_description' => 'Forum thread: ' . $thread->title,
            'page_meta_keywords' => 'forum, thread, skinbase',
        ]);
    }

    public function createThreadForm(ForumCategory $category)
    {
        return view('forum.community.new-thread', [
            'category' => $category,
            'page_title' => 'New thread',
        ]);
    }

    public function storeThread(Request $request, ForumCategory $category)
    {
        $user = Auth::user();
        abort_unless($user, 403);

        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'content' => ['required', 'string', 'min:2'],
        ]);

        $baseSlug = Str::slug((string) $validated['title']);
        $slug = $baseSlug ?: ('thread-' . time());
        $counter = 2;
        while (ForumThread::where('slug', $slug)->exists()) {
            $slug = ($baseSlug ?: 'thread') . '-' . $counter;
            $counter++;
        }

        $thread = ForumThread::create([
            'category_id' => $category->id,
            'user_id' => (int) $user->id,
            'title' => $validated['title'],
            'slug' => $slug,
            'content' => $validated['content'],
            'views' => 0,
            'is_locked' => false,
            'is_pinned' => false,
            'visibility' => 'public',
            'last_post_at' => now(),
        ]);

        ForumPost::create([
            'thread_id' => $thread->id,
            'user_id' => (int) $user->id,
            'content' => $validated['content'],
            'is_edited' => false,
            'edited_at' => null,
        ]);

        try {
            app(UserActivityService::class)->logForumPost((int) $user->id, (int) $thread->id, [
                'category_id' => (int) $category->id,
            ]);
        } catch (\Throwable) {}

        return redirect()->route('forum.thread.show', ['thread' => $thread->id, 'slug' => $thread->slug]);
    }

    public function reply(Request $request, ForumThread $thread)
    {
        $user = Auth::user();
        abort_unless($user, 403);
        abort_if($thread->is_locked, 423, 'Thread is locked.');

        $validated = $request->validate([
            'content' => ['required', 'string', 'min:2'],
        ]);

        $post = ForumPost::create([
            'thread_id' => $thread->id,
            'user_id' => (int) $user->id,
            'content' => $validated['content'],
            'is_edited' => false,
            'edited_at' => null,
        ]);

        try {
            app(UserActivityService::class)->logForumReply((int) $user->id, (int) $post->id, [
                'thread_id' => (int) $thread->id,
            ]);
        } catch (\Throwable) {}

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

        return redirect()->route('forum.thread.show', ['thread' => $thread->id, 'slug' => $thread->slug]);
    }

    public function editPostForm(ForumPost $post)
    {
        $user = Auth::user();
        abort_unless($user, 403);
        abort_unless(((int) $post->user_id === (int) $user->id) || Gate::allows('moderate-forum'), 403);

        return view('forum.community.edit-post', [
            'post' => $post,
            'thread' => $post->thread,
            'page_title' => 'Edit post',
        ]);
    }

    public function updatePost(Request $request, ForumPost $post)
    {
        $user = Auth::user();
        abort_unless($user, 403);
        abort_unless(((int) $post->user_id === (int) $user->id) || Gate::allows('moderate-forum'), 403);

        $validated = $request->validate([
            'content' => ['required', 'string', 'min:2'],
        ]);

        $post->content = $validated['content'];
        $post->is_edited = true;
        $post->edited_at = now();
        $post->save();

        return redirect()->route('forum.thread.show', ['thread' => $post->thread_id, 'slug' => $post->thread?->slug]);
    }

    public function reportPost(Request $request, ForumPost $post)
    {
        $user = Auth::user();
        abort_unless($user, 403);

        abort_if((int) $post->user_id === (int) $user->id, 422, 'You cannot report your own post.');

        $validated = $request->validate([
            'reason' => ['nullable', 'string', 'max:500'],
        ]);

        ForumPostReport::query()->updateOrCreate(
            [
                'post_id' => (int) $post->id,
                'reporter_user_id' => (int) $user->id,
            ],
            [
                'thread_id' => (int) $post->thread_id,
                'reason' => $validated['reason'] ?? null,
                'status' => 'open',
                'source_url' => (string) $request->headers->get('referer', ''),
                'reported_at' => now(),
            ]
        );

        return back()->with('status', 'Post reported. Thank you for helping moderate the forum.');
    }

    public function lockThread(ForumThread $thread)
    {
        $thread->is_locked = true;
        $thread->save();

        return back();
    }

    public function unlockThread(ForumThread $thread)
    {
        $thread->is_locked = false;
        $thread->save();

        return back();
    }

    public function pinThread(ForumThread $thread)
    {
        $thread->is_pinned = true;
        $thread->save();

        return back();
    }

    public function unpinThread(ForumThread $thread)
    {
        $thread->is_pinned = false;
        $thread->save();

        return back();
    }
}
