<?php
declare(strict_types=1);

namespace App\Models;

use PDO;

class Message extends BaseModel
{
    protected string $table = 'messages';

    public function listForConversation(int $conversationId, int $limit = 80): array
    {
        $limit = min(max($limit, 1), 120);
        $statement = $this->db()->prepare(
            'SELECT m.id,
                    m.conversation_id,
                    m.sender_id,
                    m.message_type,
                    m.body,
                    m.attachment_path,
                    m.gif_url,
                    m.link_url,
                    m.is_deleted,
                    m.status,
                    m.risk_score,
                    m.created_at,
                    m.updated_at,
                    u.username,
                    COALESCE(up.display_name, p.display_name, u.nickname, u.username) AS display_name,
                    COALESCE(up.avatar, p.avatar_path) AS avatar
             FROM messages m
             INNER JOIN users u ON u.id = m.sender_id
             LEFT JOIN user_profiles up ON up.user_id = u.id
             LEFT JOIN profiles p ON p.user_id = u.id
             WHERE m.conversation_id = :conversation_id
             ORDER BY m.created_at ASC, m.id ASC
             LIMIT :limit'
        );
        $statement->bindValue('conversation_id', $conversationId, PDO::PARAM_INT);
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->execute();

        return array_map(fn (array $row): array => $this->normalize($row), $statement->fetchAll());
    }

    public function createMessage(array $data): array
    {
        $statement = $this->db()->prepare(
            'INSERT INTO messages
                (conversation_id, sender_id, message_type, body, attachment_path, gif_url, link_url, is_deleted, status, risk_score, created_at, updated_at)
             VALUES
                (:conversation_id, :sender_id, :message_type, :body, :attachment_path, :gif_url, :link_url, 0, :status, :risk_score, NOW(), NOW())'
        );
        $statement->execute([
            'conversation_id' => (int) $data['conversation_id'],
            'sender_id' => (int) $data['sender_id'],
            'message_type' => $data['message_type'] ?? 'text',
            'body' => $data['body'] ?? null,
            'attachment_path' => $data['attachment_path'] ?? null,
            'gif_url' => $data['gif_url'] ?? null,
            'link_url' => $data['link_url'] ?? null,
            'status' => $data['status'] ?? 'sent',
            'risk_score' => (int) ($data['risk_score'] ?? 0),
        ]);

        $messageId = (int) $this->db()->lastInsertId();
        $update = $this->db()->prepare('UPDATE conversations SET updated_at = NOW() WHERE id = :id');
        $update->execute(['id' => (int) $data['conversation_id']]);

        return $this->findWithUser($messageId) ?? [];
    }

    public function softDelete(int $messageId, int $userId, bool $isAdmin = false): bool
    {
        $sql = 'UPDATE messages
                SET is_deleted = 1, status = "deleted", body = NULL, attachment_path = NULL, gif_url = NULL, link_url = NULL, updated_at = NOW()
                WHERE id = :id';
        $params = ['id' => $messageId];

        if (!$isAdmin) {
            $sql .= ' AND sender_id = :sender_id';
            $params['sender_id'] = $userId;
        }

        $statement = $this->db()->prepare($sql);
        $statement->execute($params);

        return $statement->rowCount() > 0;
    }

    public function report(int $messageId, int $reporterId, string $reason): void
    {
        $statement = $this->db()->prepare(
            'INSERT INTO message_reports (message_id, reporter_id, reason, status, created_at, updated_at)
             VALUES (:message_id, :reporter_id, :reason, "open", NOW(), NOW())'
        );
        $statement->execute([
            'message_id' => $messageId,
            'reporter_id' => $reporterId,
            'reason' => $reason,
        ]);
    }

    private function findWithUser(int $messageId): ?array
    {
        $statement = $this->db()->prepare(
            'SELECT m.id,
                    m.conversation_id,
                    m.sender_id,
                    m.message_type,
                    m.body,
                    m.attachment_path,
                    m.gif_url,
                    m.link_url,
                    m.is_deleted,
                    m.status,
                    m.risk_score,
                    m.created_at,
                    m.updated_at,
                    u.username,
                    COALESCE(up.display_name, p.display_name, u.nickname, u.username) AS display_name,
                    COALESCE(up.avatar, p.avatar_path) AS avatar
             FROM messages m
             INNER JOIN users u ON u.id = m.sender_id
             LEFT JOIN user_profiles up ON up.user_id = u.id
             LEFT JOIN profiles p ON p.user_id = u.id
             WHERE m.id = :id
             LIMIT 1'
        );
        $statement->execute(['id' => $messageId]);
        $row = $statement->fetch();

        return $row ? $this->normalize($row) : null;
    }

    private function normalize(array $row): array
    {
        $deleted = (int) ($row['is_deleted'] ?? 0) === 1 || ($row['status'] ?? '') === 'deleted';

        return [
            'id' => (int) ($row['id'] ?? 0),
            'conversation_id' => (int) ($row['conversation_id'] ?? 0),
            'sender_id' => (int) ($row['sender_id'] ?? 0),
            'message_type' => (string) ($row['message_type'] ?? 'text'),
            'body' => $deleted ? 'Bu mesaj silindi.' : (string) ($row['body'] ?? ''),
            'attachment_path' => $deleted ? null : ($row['attachment_path'] ?? null),
            'gif_url' => $deleted ? null : ($row['gif_url'] ?? null),
            'link_url' => $deleted ? null : ($row['link_url'] ?? null),
            'is_deleted' => $deleted,
            'status' => (string) ($row['status'] ?? 'sent'),
            'risk_score' => (int) ($row['risk_score'] ?? 0),
            'created_at' => (string) ($row['created_at'] ?? ''),
            'updated_at' => (string) ($row['updated_at'] ?? ''),
            'username' => (string) ($row['username'] ?? 'user'),
            'display_name' => (string) ($row['display_name'] ?? 'User'),
            'avatar' => $row['avatar'] ?? null,
        ];
    }
}
