<?php
/**
 * ITSWEBER CMS – Content Revision Model
 *
 * Stores full JSON snapshots of pages and blog posts before updates.
 * Limited to MAX_REVISIONS per content item (FIFO cleanup).
 *
 * @author    Benny Weber (ITSWEBER)
 * @copyright © ITSWEBER – www.itsweber.de
 * @contact   kontakt@itsweber.de
 */

namespace App\Models;

use App\Core\Model;

class ContentRevision extends Model
{
    protected static string $table = 'iw_content_revisions';

    private const MAX_REVISIONS = 10;

    private static ?bool $tableExistsCache = null;

    /**
     * Check if the revisions table exists (cached per request).
     */
    private static function tableExists(): bool
    {
        if (static::$tableExistsCache !== null) {
            return static::$tableExistsCache;
        }

        try {
            static::db()->query("SELECT 1 FROM " . static::$table . " LIMIT 1");
            static::$tableExistsCache = true;
        } catch (\Throwable $e) {
            static::$tableExistsCache = false;
        }

        return static::$tableExistsCache;
    }

    /**
     * Store a revision snapshot before updating content.
     */
    public static function store(string $contentType, int $contentId, array $data, ?int $changedBy = null): int
    {
        if (!static::tableExists()) {
            return 0;
        }

        if (setting('content_revisions_enabled', '1') !== '1') {
            return 0;
        }

        $id = static::create([
            'content_type' => $contentType,
            'content_id'   => $contentId,
            'title'        => $data['title'] ?? '',
            'snapshot'     => json_encode($data, JSON_UNESCAPED_UNICODE),
            'changed_by'   => $changedBy,
        ]);

        static::enforceLimit($contentType, $contentId);

        return $id;
    }

    /**
     * Get all revisions for a content item, newest first.
     * Joins user table for author name.
     */
    public static function forContent(string $contentType, int $contentId): array
    {
        if (!static::tableExists()) {
            return [];
        }

        return static::db()->fetchAll(
            "SELECT r.*, u.username AS changed_by_name
             FROM " . static::$table . " r
             LEFT JOIN iw_users u ON r.changed_by = u.id
             WHERE r.content_type = :type AND r.content_id = :cid
             ORDER BY r.created_at DESC",
            ['type' => $contentType, 'cid' => $contentId]
        );
    }

    /**
     * Count revisions for a content item.
     */
    public static function countForContent(string $contentType, int $contentId): int
    {
        if (!static::tableExists()) {
            return 0;
        }

        return (int) static::db()->fetchColumn(
            "SELECT COUNT(*) FROM " . static::$table
            . " WHERE content_type = :type AND content_id = :cid",
            ['type' => $contentType, 'cid' => $contentId]
        );
    }

    /**
     * Delete all revisions for a content item (on content delete).
     */
    public static function deleteForContent(string $contentType, int $contentId): void
    {
        if (!static::tableExists()) {
            return;
        }

        static::db()->query(
            "DELETE FROM " . static::$table
            . " WHERE content_type = :type AND content_id = :cid",
            ['type' => $contentType, 'cid' => $contentId]
        );
    }

    /**
     * Get a single revision with decoded snapshot.
     */
    public static function findWithSnapshot(int $id): ?array
    {
        $rev = static::find($id);
        if ($rev && !empty($rev['snapshot'])) {
            $rev['snapshot_data'] = json_decode($rev['snapshot'], true) ?? [];
        }
        return $rev;
    }

    /**
     * Keep only the newest MAX_REVISIONS per content item.
     */
    private static function enforceLimit(string $contentType, int $contentId): void
    {
        $count = static::countForContent($contentType, $contentId);

        if ($count <= self::MAX_REVISIONS) {
            return;
        }

        $excess = $count - self::MAX_REVISIONS;

        $oldest = static::db()->fetchAll(
            "SELECT id FROM " . static::$table
            . " WHERE content_type = :type AND content_id = :cid"
            . " ORDER BY created_at ASC LIMIT " . (int) $excess,
            ['type' => $contentType, 'cid' => $contentId]
        );

        foreach ($oldest as $row) {
            static::deleteById((int) $row['id']);
        }
    }
}
