<?php
declare(strict_types=1);

namespace ROITheme\Shared\Infrastructure\Persistence\WordPress;

use ROITheme\Shared\Domain\Contracts\ComponentDefaultsRepositoryInterface;
use ROITheme\Shared\Domain\ValueObjects\ComponentName;
use ROITheme\Shared\Domain\ValueObjects\ComponentConfiguration;

/**
 * WordPressDefaultsRepository - Defaults/Schemas desde MySQL
 *
 * RESPONSABILIDAD: Gestionar schemas de componentes (estructura, validaciones, defaults)
 *
 * TABLA: wp_roi_theme_defaults
 *
 * @package ROITheme\Infrastructure\Persistence\WordPress
 */
final class WordPressDefaultsRepository implements ComponentDefaultsRepositoryInterface
{
    private string $tableName;

    public function __construct(
        private \wpdb $wpdb
    ) {
        $this->tableName = $this->wpdb->prefix . 'roi_theme_defaults';
    }

    /**
     * Obtener configuración por defecto de un componente
     *
     * @param ComponentName $name Nombre del componente
     * @return ComponentConfiguration Configuración por defecto
     */
    public function getByName(ComponentName $name): ComponentConfiguration
    {
        $sql = $this->wpdb->prepare(
            "SELECT default_schema FROM {$this->tableName} WHERE component_name = %s LIMIT 1",
            $name->value()
        );

        $result = $this->wpdb->get_var($sql);

        if ($result === null) {
            // Return empty configuration if no defaults found
            return ComponentConfiguration::fromArray([]);
        }

        $schema = json_decode($result, true) ?? [];
        return ComponentConfiguration::fromArray($schema);
    }

    /**
     * Guardar configuración por defecto para un componente
     *
     * @param ComponentName $name Nombre del componente
     * @param ComponentConfiguration $configuration Configuración por defecto
     * @return void
     */
    public function save(ComponentName $name, ComponentConfiguration $configuration): void
    {
        $existing = $this->exists($name);

        $data = [
            'component_name' => $name->value(),
            'default_schema' => json_encode($configuration->all()),
            'updated_at' => current_time('mysql')
        ];

        if (!$existing) {
            // INSERT
            $data['created_at'] = current_time('mysql');

            $this->wpdb->insert(
                $this->tableName,
                $data,
                ['%s', '%s', '%s', '%s']
            );
        } else {
            // UPDATE
            $this->wpdb->update(
                $this->tableName,
                $data,
                ['component_name' => $name->value()],
                ['%s', '%s', '%s'],
                ['%s']
            );
        }
    }

    /**
     * Verificar si existen defaults para un componente
     *
     * @param ComponentName $name
     * @return bool
     */
    public function exists(ComponentName $name): bool
    {
        $sql = $this->wpdb->prepare(
            "SELECT COUNT(*) FROM {$this->tableName} WHERE component_name = %s",
            $name->value()
        );

        return (int) $this->wpdb->get_var($sql) > 0;
    }

    /**
     * Obtener todos los defaults
     *
     * @return array<string, ComponentConfiguration> Array asociativo nombre => configuración
     */
    public function findAll(): array
    {
        $sql = "SELECT component_name, default_schema FROM {$this->tableName}";
        $rows = $this->wpdb->get_results($sql, ARRAY_A);

        $defaults = [];
        foreach ($rows as $row) {
            $schema = json_decode($row['default_schema'], true) ?? [];
            $defaults[$row['component_name']] = ComponentConfiguration::fromArray($schema);
        }

        return $defaults;
    }

    /**
     * Eliminar defaults de un componente
     *
     * @param ComponentName $name
     * @return bool True si se eliminó, false si no existía
     */
    public function delete(ComponentName $name): bool
    {
        $result = $this->wpdb->delete(
            $this->tableName,
            ['component_name' => $name->value()],
            ['%s']
        );

        return $result !== false && $result > 0;
    }

    /**
     * Obtener schema/defaults de un componente (método legacy)
     *
     * @deprecated Use getByName() instead
     * @param string $componentName
     * @return array|null Schema del componente o null si no existe
     */
    public function find(string $componentName): ?array
    {
        $name = new ComponentName($componentName);
        if (!$this->exists($name)) {
            return null;
        }

        $config = $this->getByName($name);
        return $config->all();
    }

    /**
     * Guardar schema/defaults de un componente (método legacy)
     *
     * @deprecated Use save() instead
     * @param string $componentName
     * @param array $schema
     * @return bool
     */
    public function saveDefaults(string $componentName, array $schema): bool
    {
        $name = new ComponentName($componentName);
        $config = ComponentConfiguration::fromArray($schema);
        $this->save($name, $config);
        return true;
    }

    /**
     * Actualizar schema existente (método legacy)
     *
     * @deprecated Use save() instead
     * @param string $componentName
     * @param array $schema
     * @return bool
     */
    public function updateDefaults(string $componentName, array $schema): bool
    {
        return $this->saveDefaults($componentName, $schema);
    }

    /**
     * Eliminar defaults de un componente (método legacy)
     *
     * @deprecated Use delete() instead
     * @param string $componentName
     * @return bool
     */
    public function deleteDefaults(string $componentName): bool
    {
        $name = new ComponentName($componentName);
        return $this->delete($name);
    }
}
