<?php
declare(strict_types=1);

namespace App\Services;

use App\Core\Database;
use InvalidArgumentException;
use PDO;

final class StudioModuleService
{
    /** @return list<array<string,mixed>> */
    public function all(): array
    {
        $stmt = Database::connection()->query(
            "SELECT id, code, name, version, author, description, icon, category, status, definition_json, created_at, updated_at
             FROM axiom_studio_modules
             WHERE archived_at IS NULL
             ORDER BY updated_at DESC, name ASC"
        );
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }

    /** @param array<string,mixed> $input */
    public function create(array $input, ?int $userId): int
    {
        $code = $this->normalizeCode((string)($input['code'] ?? ''));
        $name = trim((string)($input['name'] ?? ''));
        if ($name === '') {
            throw new InvalidArgumentException('Le nom du module est obligatoire.');
        }

        $definition = [
            'schema' => 'axiom.module/1.0',
            'code' => $code,
            'name' => $name,
            'version' => trim((string)($input['version'] ?? '1.0.0')) ?: '1.0.0',
            'author' => trim((string)($input['author'] ?? 'AXIOM Studio')) ?: 'AXIOM Studio',
            'description' => trim((string)($input['description'] ?? '')),
            'icon' => trim((string)($input['icon'] ?? '◇')) ?: '◇',
            'category' => trim((string)($input['category'] ?? 'business')) ?: 'business',
            'dependencies' => [],
            'entities' => [],
            'permissions' => [],
            'routes' => [],
            'features' => [],
        ];

        $json = json_encode($definition, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
        if ($json === false) {
            throw new InvalidArgumentException('La définition du module ne peut pas être encodée.');
        }

        $stmt = Database::connection()->prepare(
            "INSERT INTO axiom_studio_modules
             (code, name, version, author, description, icon, category, status, definition_json, created_by, updated_by)
             VALUES (:code, :name, :version, :author, :description, :icon, :category, 'draft', :definition_json, :created_by, :updated_by)"
        );
        $stmt->execute([
            'code' => $code,
            'name' => $name,
            'version' => $definition['version'],
            'author' => $definition['author'],
            'description' => $definition['description'],
            'icon' => $definition['icon'],
            'category' => $definition['category'],
            'definition_json' => $json,
            'created_by' => $userId,
            'updated_by' => $userId,
        ]);

        return (int)Database::connection()->lastInsertId();
    }

    private function normalizeCode(string $code): string
    {
        $code = strtolower(trim($code));
        $code = preg_replace('/[^a-z0-9._-]+/', '-', $code) ?? '';
        $code = trim($code, '-.');
        if ($code === '' || !preg_match('/^[a-z][a-z0-9._-]{2,149}$/', $code)) {
            throw new InvalidArgumentException('Le code technique doit commencer par une lettre et contenir 3 à 150 caractères autorisés.');
        }
        return $code;
    }
}
