<?php

namespace App\Services\Messaging;

use App\Models\Message;
use App\Services\System\GlobalConfigService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class MessageCommandService
{
    public function __construct(private GlobalConfigService $configService)
    {
    }

    public function create(int $senderId, array $payload, ?UploadedFile $attachment = null): Message
    {
        $recipientId = $payload['recipient_id'] ?? null;
        if (!$recipientId && !empty($payload['recipient_role'])) {
            $recipientId = $this->recipientIdFromRole($payload['recipient_role']);
        }

        if (!$recipientId) {
            throw new RuntimeException('Recipient is required.');
        }

        if ((int) $recipientId === $senderId) {
            throw new RuntimeException('Cannot send a message to yourself.');
        }

        return DB::transaction(function () use ($senderId, $payload, $recipientId, $attachment) {
            $path = null;
            if ($attachment) {
                $path = $attachment->store('messages', ['disk' => 'public']);
            }

            $message = Message::query()->create([
                'sender_id' => $senderId,
                'recipient_id' => (int) $recipientId,
                'subject' => (string) $payload['subject'],
                'message' => (string) $payload['message'],
                'sent_datetime' => now(),
                'read_status' => 0,
                'message_number' => 'MSG-' . now()->format('YmdHis'),
                'priority' => $payload['priority'] ?? 'normal',
                'attachment' => $path,
                'status' => $payload['status'] ?? 'sent',
                'semester' => $payload['semester'] ?? $this->configService->getSemester() ?? '',
                'school_year' => $payload['school_year'] ?? $this->configService->getSchoolYear() ?? '',
            ]);

            if (!$message) {
                throw new RuntimeException('Failed to send message.');
            }

            return $message;
        });
    }

    public function update(Message $message, array $payload): Message
    {
        return DB::transaction(function () use ($message, $payload) {
            $updates = [];
            if (array_key_exists('status', $payload)) {
                $updates['status'] = $payload['status'];
            }
            if (array_key_exists('priority', $payload)) {
                $updates['priority'] = $payload['priority'];
            }
            if (array_key_exists('read_status', $payload)) {
                $read = (int) $payload['read_status'];
                $updates['read_status'] = $read;
                if ($read === 1) {
                    $updates['read_datetime'] = now();
                }
            }

            if (!empty($updates)) {
                $message->fill($updates);
                $message->save();
            }

            return $message->fresh();
        });
    }

    public function trash(Message $message): bool
    {
        return DB::transaction(function () use ($message) {
            $message->status = 'trashed';
            return (bool) $message->save();
        });
    }

    public function markRead(Message $message): bool
    {
        if ($message->read_status) {
            return true;
        }

        $message->read_status = 1;
        $message->read_datetime = now();

        return (bool) $message->save();
    }

    private function recipientIdFromRole(string $roleName): int
    {
        $map = [
            'teacher' => 1,
            'parent' => 2,
            'admin' => 3,
            'student' => 4,
            'guest' => 5,
            'administrator' => 6,
        ];

        $key = strtolower(trim($roleName));
        if (!isset($map[$key])) {
            throw new RuntimeException('Invalid recipient role.');
        }

        return $map[$key];
    }
}
