<?php

declare(strict_types=1);

final class MyronSectionComponentDefaultsRepository
{
    public function __construct(
        private readonly PDO $pdo,
    ) {
    }

    /**
     * @return array<string, mixed>|null
     */
    public function findDefault(string $componentId, string $variant = ''): ?array
    {
        $statement = $this->pdo->prepare(
            'SELECT *
             FROM section_component_defaults
             WHERE component_id = :component_id
               AND variant = :variant
             LIMIT 1'
        );
        $statement->execute([
            ':component_id' => self::normalizeComponentId($componentId),
            ':variant' => self::normalizeVariant($variant),
        ]);
        $row = $statement->fetch();

        return is_array($row) ? $this->hydrateDefault($row) : null;
    }

    /**
     * @param array<string, mixed> $content
     * @param array<string, mixed> $flags
     * @param 0|1|null $defaultContentEditable
     * @return array<string, mixed>
     */
    public function saveDefault(
        string $componentId,
        string $variant,
        array $content,
        ?int $defaultContentEditable,
        array $flags = [],
        string $actorId = ''
    ): array {
        $normalizedComponentId = self::normalizeComponentId($componentId);
        $normalizedVariant = self::normalizeVariant($variant);
        if ($normalizedComponentId === '') {
            throw new InvalidArgumentException('Section defaults require a render component ID.');
        }

        $now = myronNow();
        $contentJson = json_encode($content, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
        $flagsJson = json_encode($flags, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
        $existing = $this->findDefault($normalizedComponentId, $normalizedVariant);

        if (is_array($existing)) {
            $statement = $this->pdo->prepare(
                'UPDATE section_component_defaults
                 SET default_content_json = :default_content_json,
                     default_content_editable = :default_content_editable,
                     flags_json = :flags_json,
                     updated_by_user_id = :updated_by_user_id,
                     updated_at = :updated_at
                 WHERE component_id = :component_id
                   AND variant = :variant'
            );
            $statement->execute([
                ':default_content_json' => $contentJson,
                ':default_content_editable' => $defaultContentEditable,
                ':flags_json' => $flagsJson,
                ':updated_by_user_id' => trim($actorId),
                ':updated_at' => $now,
                ':component_id' => $normalizedComponentId,
                ':variant' => $normalizedVariant,
            ]);
        } else {
            $statement = $this->pdo->prepare(
                'INSERT INTO section_component_defaults (
                    id,
                    component_id,
                    variant,
                    default_content_json,
                    default_content_editable,
                    flags_json,
                    updated_by_user_id,
                    created_at,
                    updated_at
                 ) VALUES (
                    :id,
                    :component_id,
                    :variant,
                    :default_content_json,
                    :default_content_editable,
                    :flags_json,
                    :updated_by_user_id,
                    :created_at,
                    :updated_at
                 )'
            );
            $statement->execute([
                ':id' => myronGenerateId('secdef'),
                ':component_id' => $normalizedComponentId,
                ':variant' => $normalizedVariant,
                ':default_content_json' => $contentJson,
                ':default_content_editable' => $defaultContentEditable,
                ':flags_json' => $flagsJson,
                ':updated_by_user_id' => trim($actorId),
                ':created_at' => $now,
                ':updated_at' => $now,
            ]);
        }

        $saved = $this->findDefault($normalizedComponentId, $normalizedVariant);
        if (!is_array($saved)) {
            throw new RuntimeException('Failed to reload section component defaults.');
        }

        return $saved;
    }

    public static function identityKey(string $componentId, string $variant = ''): string
    {
        $componentId = self::normalizeComponentId($componentId);
        $variant = self::normalizeVariant($variant);

        return $variant === '' ? $componentId : $componentId . '::' . $variant;
    }

    public static function normalizeComponentId(string $componentId): string
    {
        return trim($componentId);
    }

    public static function normalizeVariant(string $variant): string
    {
        return trim($variant);
    }

    /**
     * @param array<string, mixed> $row
     * @return array<string, mixed>
     */
    private function hydrateDefault(array $row): array
    {
        $content = json_decode((string) ($row['default_content_json'] ?? '{}'), true, 512, JSON_THROW_ON_ERROR);
        $flags = json_decode((string) ($row['flags_json'] ?? '{}'), true, 512, JSON_THROW_ON_ERROR);
        $editable = $row['default_content_editable'] ?? null;

        return [
            'id' => (string) ($row['id'] ?? ''),
            'componentId' => (string) ($row['component_id'] ?? ''),
            'variant' => (string) ($row['variant'] ?? ''),
            'identityKey' => self::identityKey((string) ($row['component_id'] ?? ''), (string) ($row['variant'] ?? '')),
            'defaultContent' => is_array($content) ? $content : [],
            'defaultContentEditable' => $editable === null || $editable === '' ? null : ((int) $editable === 1 ? 1 : 0),
            'flags' => is_array($flags) ? $flags : [],
            'updatedByUserId' => (string) ($row['updated_by_user_id'] ?? ''),
            'createdAt' => (string) ($row['created_at'] ?? ''),
            'updatedAt' => (string) ($row['updated_at'] ?? ''),
        ];
    }
}
