<?php

/**
 * create the AI health record read by the KI tab, the Start checklist and get_ai_status
 *
 * @author tnt
 * @created Wed, 05 Aug 2026 22:00:00 +0100
 */

declare(strict_types=1);

namespace Plugin\tnt_mcp\Migrations;

use JTL\Plugin\Migration;
use JTL\Update\IMigration;

/**
 * Class Migration_20260805220000
 *
 * `tnt_mcp_ai_status` — one row recording how the LLM connection last behaved, so "is the AI
 * working?" can be answered without making a call.
 *
 * ## Why a sibling table and not columns on `tnt_mcp_ai_config`
 *
 * The config row is a credential: written by a human, rarely, and worth protecting. This row is
 * telemetry: written by every AI call the shop makes, including failing ones. Keeping them apart
 * means the hot write path never touches the row that holds the encrypted key, and a merchant
 * clearing their configuration does not have to reason about what happens to the health history.
 *
 * ## Why the signal is stored at all rather than tested on view
 *
 * Testing on every page view would spend the merchant's money to render an admin tab, and would
 * still be stale the moment it finished. Instead every real call reports what happened for free
 * ({@see \Plugin\tnt_mcp\src\Ai\AiStatusStore}), and a check is only *made* when the record is
 * older than the tab's TTL. No cron, no background poller.
 *
 * `down()` DROPs the table: it holds nothing a merchant typed and nothing that cannot be observed
 * again on the next call.
 */
class Migration20260805220000 extends Migration implements IMigration
{
    protected $author = 'tnt';
    // For backwards compatibility, the description property cant be strictly typed as a string
    protected $description = 'create the AI health record table';

    public function getAuthor(): ?string
    {
        return 'tnt';
    }

    public function getDescription(): string
    {
        return 'create the AI health record table';
    }

    /**
     * @inheritdoc
     */
    public function up(): void
    {
        // `lastErrorKind` is a short enum-ish string (auth|network|model|other) rather than a FK or
        // a MySQL ENUM: the set is owned by PHP, where the mapping from a provider's HTTP status to
        // a merchant-facing sentence lives, and a new kind must not need a migration.
        $this->execute("CREATE TABLE IF NOT EXISTS `tnt_mcp_ai_status` (
              `id` TINYINT UNSIGNED NOT NULL,
              `lastOkAt` DATETIME NULL DEFAULT NULL,
              `lastErrorAt` DATETIME NULL DEFAULT NULL,
              `lastErrorKind` VARCHAR(16) NOT NULL DEFAULT '',
              `lastErrorMessage` VARCHAR(255) NOT NULL DEFAULT '',
              `lastLatencyMs` INT UNSIGNED NOT NULL DEFAULT 0,
              `lastSource` VARCHAR(8) NOT NULL DEFAULT '',
              `lastCheckedAt` DATETIME NULL DEFAULT NULL,
              PRIMARY KEY (`id`)
            ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
    }

    /**
     * @inheritdoc
     */
    public function down(): void
    {
        $this->execute('DROP TABLE IF EXISTS `tnt_mcp_ai_status`');
    }
}
