<?php

namespace App\Http\Controllers\Messenger;

use App\Http\Controllers\Controller;
use App\Http\Requests\Messenger\ConversationStoreRequest;
use App\Http\Requests\Messenger\ConversationSearchRequest;
use App\Http\Requests\Messenger\ParticipantUpdateRequest;
use App\Http\Resources\Messenger\ConversationResource;
use App\Models\Messenger\Conversation;
use App\Models\Messenger\Block;
use App\Models\User;
use App\Services\Messenger\EventDispatcher;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

class ConversationController extends Controller
{
    use AuthorizesRequests;

    public function __construct(
        protected EventDispatcher $eventDispatcher
    ) {}

    public function index(Request $request): JsonResponse
    {
        $conversations = Conversation::forUser(Auth::id())
            ->with(['participants.user', 'lastMessage.user'])
            ->when($request->boolean('include_archived', false), null, function ($query) {
                $query->where('is_archived', false);
            })
            ->paginate($request->integer('limit', 20));

        return response()->json([
            'status' => 200,
            'message' => 'Conversations retrieved successfully',
            'data' => ConversationResource::collection($conversations),
            'pagination' => [
                'current_page' => $conversations->currentPage(),
                'last_page' => $conversations->lastPage(),
                'per_page' => $conversations->perPage(),
                'total' => $conversations->total(),
            ],
        ]);
    }

    public function store(ConversationStoreRequest $request): JsonResponse
    {
        try {
            DB::beginTransaction();

            $data = $request->validated();
            $userId = Auth::id();

            // Check for blocks if creating DM
            if ($data['type'] === 'dm') {
                $otherUserId = $data['participant_ids'][0];
                
                if (Block::isBlocked($userId, $otherUserId)) {
                    return response()->json([
                        'status' => 403,
                        'message' => 'Cannot create conversation with blocked user',
                    ], 403);
                }

                // Check if DM already exists
                $existingDm = Conversation::where('type', 'dm')
                    ->whereHas('participants', function ($q) use ($userId) {
                        $q->where('user_id', $userId);
                    })
                    ->whereHas('participants', function ($q) use ($otherUserId) {
                        $q->where('user_id', $otherUserId);
                    })
                    ->first();

                if ($existingDm) {
                    return response()->json([
                        'status' => 200,
                        'message' => 'Conversation already exists',
                        'data' => new ConversationResource($existingDm->load(['participants.user', 'lastMessage.user'])),
                    ]);
                }
            }

            // Create conversation
            $conversation = Conversation::create([
                'type' => $data['type'],
                'title' => $data['title'] ?? null,
                'description' => $data['description'] ?? null,
                'created_by' => $userId,
                'settings' => $data['settings'] ?? [],
            ]);

            // Handle avatar upload
            if ($request->hasFile('avatar')) {
                $avatarPath = storeMedia($request->file('avatar'), 'conversations');
                $conversation->update(['avatar' => $avatarPath]);
            }

            // Add creator as owner/member
            $conversation->addParticipant($userId, $data['type'] === 'group' ? 'owner' : 'member');

            // Add other participants
            foreach ($data['participant_ids'] as $participantId) {
                $conversation->addParticipant($participantId, 'member');
            }

            $conversation->load(['participants.user', 'lastMessage.user']);

            // Dispatch event
            $this->eventDispatcher->dispatchConversationCreated($conversation);

            DB::commit();

            return response()->json([
                'status' => 201,
                'message' => 'Conversation created successfully',
                'data' => new ConversationResource($conversation),
            ], 201);

        } catch (\Exception $e) {
            DB::rollBack();
            
            return response()->json([
                'status' => 500,
                'message' => 'Failed to create conversation',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    public function show(Conversation $conversation): JsonResponse
    {
        $this->authorize('view', $conversation);

        $conversation->load(['participants.user', 'lastMessage.user']);

        return response()->json([
            'status' => 200,
            'message' => 'Conversation retrieved successfully',
            'data' => new ConversationResource($conversation),
        ]);
    }

    public function updateParticipants(ParticipantUpdateRequest $request, Conversation $conversation): JsonResponse
    {
        try {
            $data = $request->validated();
            $userId = Auth::id();

            switch ($data['action']) {
                case 'add':
                    $this->authorize('addParticipants', $conversation);
                    
                    foreach ($data['user_ids'] as $newUserId) {
                        if (!$conversation->isParticipant($newUserId)) {
                            $conversation->addParticipant($newUserId, 'member');
                        }
                    }
                    
                    $this->eventDispatcher->dispatchParticipantAdded($conversation, $data['user_ids']);
                    $message = 'Participants added successfully';
                    break;

                case 'remove':
                    $this->authorize('removeParticipants', $conversation);
                    
                    foreach ($data['user_ids'] as $removeUserId) {
                        // Can't remove owners unless you're an owner
                        $participant = $conversation->getParticipant($removeUserId);
                        if ($participant && $participant->isOwner()) {
                            $currentParticipant = $conversation->getParticipant($userId);
                            if (!$currentParticipant || !$currentParticipant->isOwner()) {
                                continue;
                            }
                        }
                        
                        $conversation->removeParticipant($removeUserId);
                    }
                    
                    $this->eventDispatcher->dispatchParticipantRemoved($conversation, $data['user_ids']);
                    $message = 'Participants removed successfully';
                    break;

                case 'update_role':
                    $this->authorize('removeParticipants', $conversation);
                    
                    $participant = $conversation->getParticipant($data['user_id']);
                    if ($participant) {
                        $participant->update(['role' => $data['role']]);
                    }
                    
                    $message = 'Participant role updated successfully';
                    break;

                case 'mute':
                    $participant = $conversation->getParticipant($userId);
                    if ($participant) {
                        $participant->mute($data['mute_duration'] ?? null);
                    }
                    
                    $message = 'Conversation muted successfully';
                    break;

                case 'unmute':
                    $participant = $conversation->getParticipant($userId);
                    if ($participant) {
                        $participant->unmute();
                    }
                    
                    $message = 'Conversation unmuted successfully';
                    break;
            }

            $conversation->load(['participants.user']);

            return response()->json([
                'status' => 200,
                'message' => $message,
                'data' => new ConversationResource($conversation),
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'Failed to update participants',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    public function leave(Conversation $conversation): JsonResponse
    {
        $this->authorize('leave', $conversation);

        try {
            $userId = Auth::id();
            $conversation->removeParticipant($userId);

            $this->eventDispatcher->dispatchParticipantRemoved($conversation, [$userId]);

            return response()->json([
                'status' => 200,
                'message' => 'Left conversation successfully',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 500,
                'message' => 'Failed to leave conversation',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    public function search(ConversationSearchRequest $request): JsonResponse
    {
        $data = $request->validated();
        $userId = Auth::id();

        $query = Conversation::visibleTo($userId)
            ->with(['participants.user', 'lastMessage.user']);

        // Search by conversation title or participant names
        $query->where(function ($q) use ($data) {
            $q->where('title', 'like', '%' . $data['query'] . '%')
              ->orWhereHas('users', function ($userQ) use ($data) {
                  $userQ->where('first_name', 'like', '%' . $data['query'] . '%')
                       ->orWhere('last_name', 'like', '%' . $data['query'] . '%')
                       ->orWhere('username', 'like', '%' . $data['query'] . '%');
              });
        });

        // Filter by type
        if ($data['type'] !== 'all') {
            $query->where('type', $data['type']);
        }

        // Include archived
        if (!$data['include_archived']) {
            $query->where('is_archived', false);
        }

        $conversations = $query->orderBy('last_activity_at', 'desc')
                              ->limit($data['limit'])
                              ->get();

        return response()->json([
            'status' => 200,
            'message' => 'Search completed successfully',
            'data' => ConversationResource::collection($conversations),
        ]);
    }
}
