<?php
declare(strict_types=1);

namespace App\Modules\Orders;

use InvalidArgumentException;
use PDO;
use RuntimeException;

/**
 * Phase 129-01: CRUD notatek autorskich operatora (note_type='user').
 * Importowane notatki ze zrodla (shoppro/allegro/message) maja wlasne zarzadzanie
 * w OrderImportRepository::replaceNotes() — ten serwis ich nie dotyka.
 */
final class OrderNotesService
{
    private const NOTE_TYPE_USER = 'user';
    private const BODY_MAX_LENGTH = 2000;

    public function __construct(private readonly PDO $pdo)
    {
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function listUserNotes(int $orderId): array
    {
        if ($orderId <= 0) {
            return [];
        }

        $stmt = $this->pdo->prepare(
            'SELECT id, order_id, user_id, author_name, comment AS body, created_at, updated_at
             FROM order_notes
             WHERE order_id = :order_id AND note_type = :note_type
             ORDER BY created_at DESC, id DESC'
        );
        $stmt->execute(['order_id' => $orderId, 'note_type' => self::NOTE_TYPE_USER]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        return is_array($rows) ? $rows : [];
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function listImportedNotes(int $orderId): array
    {
        if ($orderId <= 0) {
            return [];
        }

        $stmt = $this->pdo->prepare(
            'SELECT * FROM order_notes
             WHERE order_id = :order_id AND note_type <> :note_type
             ORDER BY created_at_external DESC, id DESC'
        );
        $stmt->execute(['order_id' => $orderId, 'note_type' => self::NOTE_TYPE_USER]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        return is_array($rows) ? $rows : [];
    }

    public function countUserNotes(int $orderId): int
    {
        if ($orderId <= 0) {
            return 0;
        }

        $stmt = $this->pdo->prepare(
            'SELECT COUNT(*) FROM order_notes WHERE order_id = :order_id AND note_type = :note_type'
        );
        $stmt->execute(['order_id' => $orderId, 'note_type' => self::NOTE_TYPE_USER]);

        return (int) $stmt->fetchColumn();
    }

    public function findById(int $noteId): ?array
    {
        if ($noteId <= 0) {
            return null;
        }

        $stmt = $this->pdo->prepare(
            'SELECT id, order_id, user_id, author_name, comment AS body, created_at, updated_at, note_type
             FROM order_notes WHERE id = :id LIMIT 1'
        );
        $stmt->execute(['id' => $noteId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        return is_array($row) ? $row : null;
    }

    public function create(int $orderId, int $userId, string $authorName, string $body): int
    {
        $body = $this->sanitizeBody($body);
        if ($orderId <= 0 || $userId <= 0) {
            throw new InvalidArgumentException('Nieprawidlowe parametry notatki.');
        }

        $stmt = $this->pdo->prepare(
            'INSERT INTO order_notes
                (order_id, source_note_id, note_type, user_id, author_name, comment, created_at, updated_at)
             VALUES
                (:order_id, NULL, :note_type, :user_id, :author_name, :comment, NOW(), NOW())'
        );
        $stmt->execute([
            'order_id' => $orderId,
            'note_type' => self::NOTE_TYPE_USER,
            'user_id' => $userId,
            'author_name' => $authorName !== '' ? $authorName : null,
            'comment' => $body,
        ]);

        return (int) $this->pdo->lastInsertId();
    }

    /**
     * @throws RuntimeException kod 403 gdy uzytkownik nie jest autorem notatki
     */
    public function update(int $noteId, int $userId, string $body): void
    {
        $body = $this->sanitizeBody($body);
        if ($noteId <= 0 || $userId <= 0) {
            throw new InvalidArgumentException('Nieprawidlowe parametry notatki.');
        }

        $stmt = $this->pdo->prepare(
            'UPDATE order_notes
             SET comment = :comment, updated_at = NOW()
             WHERE id = :id AND note_type = :note_type AND user_id = :user_id'
        );
        $stmt->execute([
            'id' => $noteId,
            'note_type' => self::NOTE_TYPE_USER,
            'user_id' => $userId,
            'comment' => $body,
        ]);

        if ($stmt->rowCount() === 0) {
            throw new RuntimeException('Brak uprawnien — tylko autor moze edytowac notatke.', 403);
        }
    }

    /**
     * @throws RuntimeException kod 403 gdy uzytkownik nie jest autorem notatki
     */
    public function delete(int $noteId, int $userId): void
    {
        if ($noteId <= 0 || $userId <= 0) {
            throw new InvalidArgumentException('Nieprawidlowe parametry notatki.');
        }

        $stmt = $this->pdo->prepare(
            'DELETE FROM order_notes
             WHERE id = :id AND note_type = :note_type AND user_id = :user_id'
        );
        $stmt->execute([
            'id' => $noteId,
            'note_type' => self::NOTE_TYPE_USER,
            'user_id' => $userId,
        ]);

        if ($stmt->rowCount() === 0) {
            throw new RuntimeException('Brak uprawnien — tylko autor moze usunac notatke.', 403);
        }
    }

    private function sanitizeBody(string $body): string
    {
        $body = trim($body);
        if ($body === '') {
            throw new InvalidArgumentException('Tresc notatki nie moze byc pusta.');
        }
        if (function_exists('mb_strlen') ? mb_strlen($body) > self::BODY_MAX_LENGTH : strlen($body) > self::BODY_MAX_LENGTH) {
            throw new InvalidArgumentException('Tresc notatki przekracza ' . self::BODY_MAX_LENGTH . ' znakow.');
        }

        return $body;
    }
}
