<?php

declare(strict_types=1);

namespace App\Models;

use DateTime;

/**
 * Modèle Post pour un blog en production.
 *
 * Encapsule la logique métier et la validation des articles.
 */
final class Post
{
    private DateTime $createdAt;
    private DateTime $updatedAt;

    public function __construct(
        private readonly int $id,
        private readonly string $title,
        private readonly string $content,
        ?DateTime $createdAt = null,
        ?DateTime $updatedAt = null,
    ) {
        $this->createdAt = $createdAt ?? new DateTime();
        $this->updatedAt = $updatedAt ?? new DateTime();

        $this->validate();
    }

    /**
     * Crée une instance depuis un tableau (ligne DB ou formulaire).
     *
     * @param array<string,mixed> $data
     * @return self
     */
    public static function fromArray(array $data): self
    {
        $id = (int)($data['id'] ?? 0);
        $title = (string)($data['title'] ?? '');
        $content = (string)($data['content'] ?? '');

        $createdAt = isset($data['created_at'])
            ? new DateTime($data['created_at'])
            : new DateTime();

        $updatedAt = isset($data['updated_at'])
            ? new DateTime($data['updated_at'])
            : new DateTime();

        return new self($id, $title, $content, $createdAt, $updatedAt);
    }

    /**
     * Valide les données du post.
     *
     * @throws \InvalidArgumentException
     */
    private function validate(): void
    {
        if (empty($this->title)) {
            throw new \InvalidArgumentException('Le titre ne peut pas être vide');
        }

        if (mb_strlen($this->title) > 255) {
            throw new \InvalidArgumentException('Le titre ne peut pas dépasser 255 caractères');
        }

        if (empty($this->content)) {
            throw new \InvalidArgumentException('Le contenu ne peut pas être vide');
        }

        if (mb_strlen($this->content) > 65535) {
            throw new \InvalidArgumentException('Le contenu ne peut pas dépasser 65535 caractères');
        }
    }

    // ============================================
    // Getters
    // ============================================

    public function getId(): int
    {
        return $this->id;
    }

    public function getTitle(): string
    {
        return $this->title;
    }

    public function getContent(): string
    {
        return $this->content;
    }

    public function getCreatedAt(): DateTime
    {
        return $this->createdAt;
    }

    public function getUpdatedAt(): DateTime
    {
        return $this->updatedAt;
    }

    // ============================================
    // Logique métier
    // ============================================

    /**
     * Retourne un extrait du contenu (sans HTML).
     *
     * @param int $length Longueur maximale en caractères
     * @return string
     */
    public function getExcerpt(int $length = 150): string
    {
        $text = strip_tags($this->content);
        return mb_strlen($text) > $length
            ? mb_substr($text, 0, $length) . '...'
            : $text;
    }

    /**
     * Retourne un slug (URL-friendly) du titre.
     *
     * @return string
     */
    public function getSlug(): string
    {
        $slug = strtolower($this->title);
        $slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
        return trim($slug, '-');
    }

    /**
     * Indique si l'article a été créé récemment.
     *
     * @param int $days Nombre de jours
     * @return bool
     */
    public function isRecent(int $days = 7): bool
    {
        $limit = new DateTime("-{$days} days");
        return $this->createdAt > $limit;
    }

    /**
     * Retourne les données prêtes à persister en DB.
     *
     * @return array{title:string,content:string}
     */
    public function toPersistableArray(): array
    {
        return [
            'title' => $this->title,
            'content' => $this->content,
        ];
    }
}
