<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\{Auth, Csrf, Database, Response, Upload};
use App\Models\{Conversation, Friendship, Message};
use App\Services\Security\ZaloroxShield;
use Throwable;

class MessageController extends BaseController
{
    public function conversations(): Response
    {
        $userId = Auth::id();
        if (!$userId) {
            return $this->jsonError('Giris yapmalisin.', 403);
        }

        try {
            return Response::json(['ok' => true, 'conversations' => (new Conversation())->listForUser($userId)]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'messages.conversations');
            return $this->jsonError('Konusmalar su anda yuklenemedi.', 500);
        }
    }

    public function thread(int|string $conversationId): Response
    {
        $userId = Auth::id();
        if (!$userId) {
            return $this->jsonError('Giris yapmalisin.', 403);
        }

        $conversationId = (int) $conversationId;
        try {
            $conversations = new Conversation();
            if (!$conversations->userCanAccess($conversationId, $userId)) {
                return $this->jsonError('Bu konusmaya erisimin yok.', 403);
            }

            $conversations->markRead($conversationId, $userId);

            return Response::json([
                'ok' => true,
                'messages' => (new Message())->listForConversation($conversationId),
                'participants' => $conversations->participants($conversationId),
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'messages.thread');
            return $this->jsonError('Mesajlar su anda yuklenemedi.', 500);
        }
    }

    public function send(): Response
    {
        $userId = Auth::id();
        if (!$userId) {
            return $this->jsonError('Giris yapmalisin.', 403);
        }

        if (!Csrf::verify($this->input('_csrf'))) {
            return $this->jsonError('Guvenlik oturumu yenilenmeli.', 419);
        }

        $conversationId = (int) $this->input('conversation_id', 0);
        $targetUserId = (int) $this->input('user_id', $this->input('receiver_id', 0));
        $type = (string) $this->input('message_type', 'text');
        $body = trim((string) $this->input('body', ''));
        $attachmentPath = trim((string) $this->input('attachment_path', '')) ?: null;
        $gifUrl = trim((string) $this->input('gif_url', '')) ?: null;

        if (!in_array($type, ['text', 'emoji', 'gif', 'image', 'link'], true)) {
            $type = 'text';
        }

        if ($body === '' && $attachmentPath === null && $gifUrl === null) {
            return $this->jsonError('Bos mesaj gonderilemez.', 422);
        }

        if (strlen($body) > 3000) {
            return $this->jsonError('Mesaj 3000 karakterden kisa olmali.', 422);
        }

        try {
            $conversations = new Conversation();
            $friendships = new Friendship();

            if ($conversationId <= 0) {
                if ($targetUserId <= 0) {
                    return $this->jsonError('Mesaj alicisi secilmedi.', 422);
                }

                if ($friendships->isBlockedBetween($userId, $targetUserId)) {
                    return $this->jsonError('Bu kullanici ile mesajlasamazsin.', 403);
                }

                $messagePermission = $this->canMessageTarget($userId, $targetUserId, $friendships);
                if (!$messagePermission['allowed']) {
                    return $this->jsonError($messagePermission['message'], 403);
                }

                $conversationId = $conversations->findOrCreatePrivate($userId, $targetUserId);
            } else {
                if (!$conversations->userCanAccess($conversationId, $userId)) {
                    return $this->jsonError('Bu konusmaya erisimin yok.', 403);
                }

                foreach ($conversations->participants($conversationId) as $participantId) {
                    if ($participantId !== $userId && $friendships->isBlockedBetween($userId, $participantId)) {
                        return $this->jsonError('Bu kullanici ile mesajlasamazsin.', 403);
                    }

                    if ($participantId !== $userId) {
                        $messagePermission = $this->canMessageTarget($userId, $participantId, $friendships);
                        if (!$messagePermission['allowed']) {
                            return $this->jsonError($messagePermission['message'], 403);
                        }
                    }
                }
            }

            $scanText = $body !== '' ? $body : ($gifUrl ?? $attachmentPath ?? '');
            $scan = (new ZaloroxShield($this->config))->scanMessage($scanText, $userId);
            $status = match ((string) ($scan['action_taken'] ?? 'allow')) {
                'blocked' => 'blocked',
                'pending_review' => 'pending_review',
                default => 'sent',
            };

            $message = (new Message())->createMessage([
                'conversation_id' => $conversationId,
                'sender_id' => $userId,
                'message_type' => $gifUrl ? 'gif' : ($attachmentPath ? 'image' : $type),
                'body' => $body,
                'attachment_path' => $attachmentPath,
                'gif_url' => $gifUrl,
                'link_url' => $this->extractFirstUrl($body),
                'status' => $status,
                'risk_score' => (int) ($scan['risk_score'] ?? 0),
            ]);

            if ($status === 'blocked') {
                return Response::json([
                    'ok' => false,
                    'status' => 'blocked',
                    'message' => 'Zalorox Shield bu mesaji engelledi.',
                    'message_item' => $message,
                ], 422);
            }

            return Response::json([
                'ok' => true,
                'status' => $status,
                'message' => $status === 'pending_review' ? 'Mesaj incelemeye alindi.' : 'Mesaj gonderildi.',
                'conversation_id' => $conversationId,
                'message_item' => $message,
            ]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'messages.send');
            return $this->jsonError('Mesaj su anda gonderilemedi.', 500);
        }
    }

    public function delete(): Response
    {
        $userId = Auth::id();
        if (!$userId) {
            return $this->jsonError('Giris yapmalisin.', 403);
        }

        if (!Csrf::verify($this->input('_csrf'))) {
            return $this->jsonError('Guvenlik oturumu yenilenmeli.', 419);
        }

        try {
            $deleted = (new Message())->softDelete(
                (int) $this->input('message_id', $this->input('id', 0)),
                $userId,
                Auth::role('admin')
            );

            return Response::json(['ok' => $deleted, 'message' => $deleted ? 'Mesaj silindi.' : 'Mesaj bulunamadi.'], $deleted ? 200 : 404);
        } catch (Throwable $exception) {
            $this->logException($exception, 'messages.delete');
            return $this->jsonError('Mesaj su anda silinemedi.', 500);
        }
    }

    public function read(): Response
    {
        $userId = Auth::id();
        if (!$userId) {
            return $this->jsonError('Giris yapmalisin.', 403);
        }

        if (!Csrf::verify($this->input('_csrf'))) {
            return $this->jsonError('Guvenlik oturumu yenilenmeli.', 419);
        }

        $conversationId = (int) $this->input('conversation_id', 0);

        try {
            $conversations = new Conversation();
            if (!$conversations->userCanAccess($conversationId, $userId)) {
                return $this->jsonError('Bu konusmaya erisimin yok.', 403);
            }

            $conversations->markRead($conversationId, $userId);
            return Response::json(['ok' => true, 'message' => 'Okundu olarak isaretlendi.']);
        } catch (Throwable $exception) {
            $this->logException($exception, 'messages.read');
            return $this->jsonError('Okundu bilgisi kaydedilemedi.', 500);
        }
    }

    public function upload(): Response
    {
        $userId = Auth::id();
        if (!$userId) {
            return $this->jsonError('Giris yapmalisin.', 403);
        }

        if (!Csrf::verify($_POST['_csrf'] ?? null)) {
            return $this->jsonError('Guvenlik oturumu yenilenmeli.', 419);
        }

        $file = $_FILES['file'] ?? null;
        if (!is_array($file) || ($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
            return $this->jsonError('Dosya yuklenemedi.', 422);
        }

        if (($file['size'] ?? 0) > 5 * 1024 * 1024 || !Upload::validImage($file)) {
            return $this->jsonError('Sadece 5MB altinda JPG, PNG, WEBP veya GIF yuklenebilir.', 422);
        }

        try {
            $directory = ($this->config['paths']['uploads'] ?? BASE_PATH . '/public/uploads') . '/messages/' . date('Y/m');
            if (!is_dir($directory)) {
                @mkdir($directory, 0775, true);
            }

            $extension = strtolower(pathinfo((string) $file['name'], PATHINFO_EXTENSION));
            $extension = in_array($extension, ['jpg', 'jpeg', 'png', 'webp', 'gif'], true) ? $extension : 'jpg';
            $name = 'msg-' . $userId . '-' . bin2hex(random_bytes(8)) . '.' . $extension;
            $target = $directory . '/' . $name;

            if (!move_uploaded_file((string) $file['tmp_name'], $target)) {
                return $this->jsonError('Dosya kaydedilemedi.', 500);
            }

            $publicPath = '/uploads/messages/' . date('Y/m') . '/' . $name;
            return Response::json(['ok' => true, 'path' => $publicPath]);
        } catch (Throwable $exception) {
            $this->logException($exception, 'messages.upload');
            return $this->jsonError('Dosya su anda yuklenemedi.', 500);
        }
    }

    public function gifs(): Response
    {
        return Response::json([
            'ok' => true,
            'gifs' => [
                ['title' => 'Zalorox Pulse', 'url' => '/assets/img/logo.gif'],
                ['title' => 'Studio Logo', 'url' => '/assets/img/logo-studio.png'],
                ['title' => 'Music Logo', 'url' => '/assets/img/logo-music.png'],
            ],
            'todo' => 'Giphy/Tenor provider adapter sonraki iterasyonda eklenecek.',
        ]);
    }

    private function input(string $key, mixed $default = null): mixed
    {
        static $json = null;

        if (array_key_exists($key, $_POST)) {
            return $_POST[$key];
        }

        if ($json === null) {
            $decoded = json_decode(file_get_contents('php://input') ?: '', true);
            $json = is_array($decoded) ? $decoded : [];
        }

        return $json[$key] ?? $default;
    }

    private function extractFirstUrl(string $body): ?string
    {
        if (preg_match('~https?://[^\s<>"\']+~i', $body, $match)) {
            return $match[0];
        }

        return null;
    }

    private function canMessageTarget(int $senderId, int $targetId, Friendship $friendships): array
    {
        if ($senderId <= 0 || $targetId <= 0 || $senderId === $targetId) {
            return ['allowed' => false, 'message' => 'Mesaj alicisi gecersiz.'];
        }

        if (Auth::role('admin')) {
            return ['allowed' => true, 'message' => ''];
        }

        $statement = Database::connection($this->config)->prepare(
            'SELECT COALESCE(NULLIF(up.message_privacy, ""), "everyone") AS message_privacy
             FROM users u
             LEFT JOIN user_profiles up ON up.user_id = u.id
             WHERE u.id = :target_id AND u.status = "active"
             LIMIT 1'
        );
        $statement->execute(['target_id' => $targetId]);
        $messagePrivacy = (string) ($statement->fetchColumn() ?: 'everyone');

        if ($messagePrivacy === 'members') {
            $messagePrivacy = 'everyone';
        }

        if ($messagePrivacy === 'everyone') {
            return ['allowed' => true, 'message' => ''];
        }

        if ($messagePrivacy === 'friends') {
            return ($friendships->relationship($senderId, $targetId)['state'] ?? '') === 'friends'
                ? ['allowed' => true, 'message' => '']
                : ['allowed' => false, 'message' => 'Bu kullanici sadece arkadaslarindan mesaj kabul ediyor.'];
        }

        return ['allowed' => false, 'message' => 'Bu kullanici mesaj alimini kapatmis.'];
    }

    private function jsonError(string $message, int $status): Response
    {
        return Response::json(['ok' => false, 'message' => $message], $status);
    }
}
