<?php

namespace App\Http\Controllers\Messenger;

use App\Http\Controllers\Controller;
use App\Http\Requests\Messenger\MessageStoreRequest;
use App\Http\Requests\Messenger\MessageUpdateRequest;
use App\Http\Resources\Messenger\MessageResource;
use App\Models\Messenger\Conversation;
use App\Models\Messenger\Message;
use App\Models\Messenger\MessageAttachment;
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 MessageController extends Controller
{
    use AuthorizesRequests;

    public function __construct(
        protected EventDispatcher $eventDispatcher
    ) {}

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

        $limit = min($request->integer('limit', 50), 100);
        $cursor = $request->integer('cursor');

        $messages = Message::inConversation($conversation->id)
            ->notDeleted()
            ->with(['user', 'attachments', 'replyToMessage.user'])
            ->when($cursor, function ($query) use ($cursor) {
                $query->where('id', '<', $cursor);
            })
            ->orderBy('id', 'desc')
            ->limit($limit)
            ->get();

        $nextCursor = $messages->count() === $limit ? $messages->last()->id : null;

        return response()->json([
            'status' => 200,
            'message' => 'Messages retrieved successfully',
            'data' => MessageResource::collection($messages),
            'pagination' => [
                'limit' => $limit,
                'cursor' => $cursor,
                'next_cursor' => $nextCursor,
                'has_more' => !is_null($nextCursor),
            ],
        ]);
    }

    public function store(MessageStoreRequest $request, Conversation $conversation): JsonResponse
    {
        $this->authorize('sendMessage', $conversation);

        try {
            DB::beginTransaction();

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

            // Check for existing message with same client_generated_id (idempotency)
            $existingMessage = Message::where('user_id', $userId)
                ->where('client_generated_id', $data['client_generated_id'])
                ->first();

            if ($existingMessage) {
                DB::rollBack();
                return response()->json([
                    'status' => 200,
                    'message' => 'Message already exists',
                    'data' => new MessageResource($existingMessage->load(['user', 'attachments'])),
                ]);
            }

            // Validate reply_to_message if provided
            if ($data['reply_to_message_id']) {
                $replyToMessage = Message::where('id', $data['reply_to_message_id'])
                    ->where('conversation_id', $conversation->id)
                    ->where('is_deleted', false)
                    ->first();

                if (!$replyToMessage) {
                    return response()->json([
                        'status' => 422,
                        'message' => 'Reply target message not found or deleted',
                    ], 422);
                }
            }

            // Create message
            $message = Message::create([
                'conversation_id' => $conversation->id,
                'user_id' => $userId,
                'type' => $data['type'],
                'content' => $data['content'],
                'client_generated_id' => $data['client_generated_id'],
                'reply_to_message_id' => $data['reply_to_message_id'],
                'metadata' => $data['metadata'] ?? null,
            ]);

            // Handle attachments
            if ($request->hasFile('attachments')) {
                foreach ($request->file('attachments') as $file) {
                    $this->storeAttachment($message, $file);
                }
            }

            // Update conversation last activity
            $conversation->update([
                'last_message_id' => $message->id,
                'last_activity_at' => now(),
            ]);

            $message->load(['user', 'attachments', 'replyToMessage.user']);

            // Mark as delivered for sender and dispatch event
            $message->markAsDelivered($userId);
            $this->eventDispatcher->dispatchMessageSent($message);

            DB::commit();

            return response()->json([
                'status' => 201,
                'message' => 'Message sent successfully',
                'data' => new MessageResource($message),
            ], 201);

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

    public function update(MessageUpdateRequest $request, Message $message): JsonResponse
    {
        $this->authorize('update', $message);

        try {
            $data = $request->validated();
            
            $message->edit($data['content']);
            $message->load(['user', 'attachments']);

            $this->eventDispatcher->dispatchMessageUpdated($message);

            return response()->json([
                'status' => 200,
                'message' => 'Message updated successfully',
                'data' => new MessageResource($message),
            ]);

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

    public function destroy(Message $message): JsonResponse
    {
        $this->authorize('delete', $message);

        try {
            $message->softDelete();
            
            $this->eventDispatcher->dispatchMessageDeleted($message);

            return response()->json([
                'status' => 200,
                'message' => 'Message deleted successfully',
            ]);

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

    protected function storeAttachment(Message $message, $file): MessageAttachment
    {
        $type = 'document'; // default
        $mimeType = $file->getMimeType();
        
        if (str_starts_with($mimeType, 'image/')) {
            $type = 'image';
        } elseif (str_starts_with($mimeType, 'video/')) {
            $type = 'video';
        } elseif (str_starts_with($mimeType, 'audio/')) {
            $type = 'audio';
        }

        $filePath = storeMedia($file, "messages/{$type}s");
        
        return MessageAttachment::create([
            'message_id' => $message->id,
            'type' => $type,
            'file_name' => $file->getClientOriginalName(),
            'file_path' => $filePath,
            'mime_type' => $mimeType,
            'file_size' => $file->getSize(),
            'storage_driver' => 'public',
        ]);
    }
}
