<?php

namespace App\Http\Controllers\Api\Messaging;

use App\Http\Controllers\Api\BaseApiController;
use App\Http\Requests\Messaging\MessageIndexRequest;
use App\Http\Requests\Messaging\MessageSendRequest;
use App\Http\Requests\Messaging\MessageUpdateRequest;
use App\Http\Resources\Messaging\MessageCollection;
use App\Http\Resources\Messaging\MessageResource;
use App\Http\Resources\Messaging\RecipientResource;
use App\Models\Message;
use App\Services\Messaging\MessageCommandService;
use App\Services\Messaging\MessageQueryService;
use App\Services\Messaging\MessageRecipientService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class MessagesController extends BaseApiController
{
    public function __construct(
        private MessageQueryService $queryService,
        private MessageCommandService $commandService,
        private MessageRecipientService $recipientService
    ) {
        parent::__construct();
    }

    public function index(MessageIndexRequest $request): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        if ($userId <= 0) {
            return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
        }

        $filters = $request->validated();
        $page = (int) ($filters['page'] ?? 1);
        $perPage = (int) ($filters['per_page'] ?? 20);

        $this->authorize('viewAny', Message::class);

        $role = $this->queryService->getUserRoleName($userId);
        $messages = $this->queryService->inbox($userId, $filters, $page, $perPage);
        $collection = new MessageCollection($messages);
        $meta = $collection->with($request)['meta'] ?? null;

        return $this->success([
            'role' => $role,
            'messages' => $collection->toArray($request),
            'meta' => $meta,
        ]);
    }

    public function inbox(MessageIndexRequest $request): JsonResponse
    {
        return $this->listMessages($request, 'inbox');
    }

    public function sent(MessageIndexRequest $request): JsonResponse
    {
        return $this->listMessages($request, 'sent');
    }

    public function drafts(MessageIndexRequest $request): JsonResponse
    {
        return $this->listMessages($request, 'drafts');
    }

    public function trash(MessageIndexRequest $request): JsonResponse
    {
        return $this->listMessages($request, 'trash');
    }

    public function show(int $id): JsonResponse
    {
        $message = $this->queryService->findForUser($id);
        if (!$message) {
            return $this->error('Message not found.', Response::HTTP_NOT_FOUND);
        }

        $this->authorize('view', $message);

        $userId = (int) (auth()->id() ?? 0);
        if ($message->recipient_id === $userId) {
            $this->commandService->markRead($message);
            $message->refresh();
        }

        return $this->success([
            'message' => new MessageResource($message),
        ]);
    }

    public function store(MessageSendRequest $request): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        if ($userId <= 0) {
            return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
        }

        $this->authorize('create', Message::class);

        try {
            $message = $this->commandService->create($userId, $request->validated(), $request->file('attachment'));
        } catch (\Throwable $e) {
            Log::error('Message send failed: ' . $e->getMessage());
            return $this->error($e->getMessage(), Response::HTTP_BAD_REQUEST);
        }

        return $this->success([
            'message' => new MessageResource($message->fresh(['sender', 'recipient'])),
        ], 'Message sent.', Response::HTTP_CREATED);
    }

    public function receive(): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        if ($userId <= 0) {
            return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
        }

        $messages = $this->queryService->receivedAndMarkRead($userId);

        return $this->success([
            'messages' => (new MessageCollection(collect($messages)))->toArray(request()),
        ]);
    }

    public function recipients(string $type): JsonResponse
    {
        $type = strtolower(trim($type));
        $data = match ($type) {
            'teacher' => $this->recipientService->teachers(),
            'parent' => $this->recipientService->parents(),
            default => null,
        };

        if ($data === null) {
            return $this->error('Invalid recipient type.', Response::HTTP_BAD_REQUEST);
        }

        $payload = array_map(fn ($row) => (new RecipientResource($row))->toArray(request()), $data);

        return $this->success([
            'recipients' => $payload,
        ]);
    }

    public function update(MessageUpdateRequest $request, int $id): JsonResponse
    {
        $message = Message::query()->find($id);
        if (!$message) {
            return $this->error('Message not found.', Response::HTTP_NOT_FOUND);
        }

        $this->authorize('update', $message);

        try {
            $updated = $this->commandService->update($message, $request->validated());
        } catch (\Throwable $e) {
            Log::error('Message update failed: ' . $e->getMessage());
            return $this->error('Unable to update message.', Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        return $this->success([
            'message' => new MessageResource($updated->load(['sender', 'recipient'])),
        ], 'Message updated.');
    }

    public function destroy(int $id): JsonResponse
    {
        $message = Message::query()->find($id);
        if (!$message) {
            return $this->error('Message not found.', Response::HTTP_NOT_FOUND);
        }

        $this->authorize('delete', $message);

        try {
            $trashed = $this->commandService->trash($message);
        } catch (\Throwable $e) {
            Log::error('Message delete failed: ' . $e->getMessage());
            return $this->error('Unable to delete message.', Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        if (!$trashed) {
            return $this->error('Unable to delete message.', Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        return $this->success(null, 'Message deleted.');
    }

    private function listMessages(MessageIndexRequest $request, string $bucket): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        if ($userId <= 0) {
            return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
        }

        $filters = $request->validated();
        $page = (int) ($filters['page'] ?? 1);
        $perPage = (int) ($filters['per_page'] ?? 20);

        $this->authorize('viewAny', Message::class);

        $paginator = match ($bucket) {
            'sent' => $this->queryService->sent($userId, $filters, $page, $perPage),
            'drafts' => $this->queryService->drafts($userId, $filters, $page, $perPage),
            'trash' => $this->queryService->trash($userId, $filters, $page, $perPage),
            default => $this->queryService->inbox($userId, $filters, $page, $perPage),
        };

        $collection = new MessageCollection($paginator);
        $meta = $collection->with($request)['meta'] ?? null;

        return $this->success([
            'messages' => $collection->toArray($request),
            'meta' => $meta,
        ]);
    }
}
