<?php

namespace App\Http\Controllers\Epelcon;

use App\Http\Controllers\Controller;
use App\Models\Message;
use App\Models\MessageThread;
use App\Models\ThreadParticipant;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class InboxController extends Controller
{
    public function index(Request $request)
    {
        return $this->render($request, null);
    }

    public function show(Request $request, MessageThread $thread)
    {
        return $this->render($request, $thread);
    }

    protected function render(Request $request, ?MessageThread $thread)
    {
        $user = Auth::user();

        // If a thread id is passed via query and no explicit thread, resolve it.
        if (! $thread && $request->filled('thread')) {
            $thread = MessageThread::find($request->integer('thread'));
        }

        $threads = MessageThread::query()
            ->whereIn('kind', ['dm', 'group', 'announcement'])
            ->whereHas('participants', fn ($q) => $q->where('user_id', $user->id))
            ->with(['latestMessage', 'participants.user'])
            ->orderByDesc('last_message_at')
            ->orderByDesc('id')
            ->limit(80)
            ->get();

        $unread = [];
        foreach ($threads as $t) {
            $unread[$t->id] = $t->unreadCountFor($user);
        }

        $messages = collect();
        $participant = null;

        if ($thread) {
            // Ensure user is a participant OR is admin/manager
            $participant = ThreadParticipant::where('message_thread_id', $thread->id)
                ->where('user_id', $user->id)
                ->first();

            if (! $participant && ! $user->hasRole('admin', 'manager')) {
                return redirect()->route('epelcon.inbox')->with('error', 'You do not have access to that conversation.');
            }

            $messages = $thread->messages()->orderBy('created_at')->limit(500)->get();

            if ($participant) {
                $participant->update(['last_read_at' => now()]);
                $unread[$thread->id] = 0;
            }
        }

        $staffOptions = User::query()
            ->whereIn('role', array_keys(User::STAFF_ROLES))
            ->where('id', '!=', $user->id)
            ->orderBy('name')
            ->get(['id', 'name', 'role']);

        return view('epelcon.inbox.index', [
            'threads' => $threads,
            'unread' => $unread,
            'currentThread' => $thread,
            'messages' => $messages,
            'staffOptions' => $staffOptions,
            'canBroadcast' => $user->hasRole('admin', 'manager'),
        ]);
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'subject' => 'required|string|max:200',
            'kind' => 'required|in:dm,group,announcement',
            'participants' => 'required|array|min:1',
            'participants.*' => 'integer|exists:users,id',
            'body' => 'required|string|max:5000',
        ]);

        $user = Auth::user();

        $thread = MessageThread::create([
            'subject' => $data['subject'],
            'kind' => $data['kind'],
            'created_by' => $user->id,
            'last_message_at' => now(),
            'is_public' => false,
        ]);

        $participants = collect($data['participants'])->push($user->id)->unique();

        foreach ($participants as $uid) {
            ThreadParticipant::create([
                'message_thread_id' => $thread->id,
                'user_id' => (int) $uid,
                'joined_at' => now(),
                'last_read_at' => (int) $uid === $user->id ? now() : null,
            ]);
        }

        Message::create([
            'message_thread_id' => $thread->id,
            'sender_user_id' => $user->id,
            'sender_name' => $user->name,
            'body' => $data['body'],
        ]);

        return redirect()->route('epelcon.inbox.show', $thread)
            ->with('success', 'Message sent.');
    }

    public function reply(Request $request, MessageThread $thread)
    {
        $data = $request->validate([
            'body' => 'required|string|max:5000',
        ]);

        $user = Auth::user();

        $participant = ThreadParticipant::where('message_thread_id', $thread->id)
            ->where('user_id', $user->id)
            ->first();

        if (! $participant && ! $user->hasRole('admin', 'manager')) {
            return back()->with('error', 'You do not have access to that conversation.');
        }

        Message::create([
            'message_thread_id' => $thread->id,
            'sender_user_id' => $user->id,
            'sender_name' => $user->name,
            'body' => $data['body'],
        ]);

        $thread->update(['last_message_at' => now()]);

        if ($participant) {
            $participant->update(['last_read_at' => now()]);
        }

        return redirect()->route('epelcon.inbox.show', $thread);
    }

    public function markRead(Request $request, MessageThread $thread)
    {
        $user = Auth::user();

        ThreadParticipant::where('message_thread_id', $thread->id)
            ->where('user_id', $user->id)
            ->update(['last_read_at' => now()]);

        if ($request->wantsJson()) {
            return response()->json(['ok' => true]);
        }

        return back();
    }

    public function announce(Request $request)
    {
        $user = Auth::user();

        if (! $user->hasRole('admin', 'manager')) {
            abort(403, 'Only managers and administrators may broadcast announcements.');
        }

        $data = $request->validate([
            'subject' => 'required|string|max:200',
            'body' => 'required|string|max:5000',
        ]);

        $thread = MessageThread::create([
            'subject' => $data['subject'],
            'kind' => 'announcement',
            'created_by' => $user->id,
            'last_message_at' => now(),
            'is_public' => false,
        ]);

        $staffIds = User::whereIn('role', array_keys(User::STAFF_ROLES))
            ->pluck('id')
            ->push($user->id)
            ->unique();

        foreach ($staffIds as $uid) {
            ThreadParticipant::create([
                'message_thread_id' => $thread->id,
                'user_id' => (int) $uid,
                'joined_at' => now(),
                'last_read_at' => (int) $uid === $user->id ? now() : null,
            ]);
        }

        Message::create([
            'message_thread_id' => $thread->id,
            'sender_user_id' => $user->id,
            'sender_name' => $user->name,
            'body' => $data['body'],
        ]);

        return redirect()->route('epelcon.inbox.show', $thread)
            ->with('success', 'Announcement broadcast to all staff.');
    }
}
