<?php
declare(strict_types=1);

namespace ROITheme\Shared\Domain\Contracts;

use ROITheme\Shared\Domain\Entities\Component;
use ROITheme\Shared\Domain\ValueObjects\ComponentName;
use ROITheme\Shared\Domain\Exceptions\ComponentNotFoundException;

/**
 * ComponentRepositoryInterface - Contrato para persistencia de componentes
 *
 * RESPONSABILIDAD: Definir contrato para operaciones CRUD de componentes
 *
 * INVERSIÓN DE DEPENDENCIAS:
 * - Esta interfaz está en Domain (núcleo)
 * - Infrastructure implementa esta interfaz
 * - Application depende de esta interfaz (NO de la implementación)
 *
 * IMPLEMENTACIONES ESPERADAS:
 * - WordPressComponentRepository (usa wpdb y tablas WP)
 * - InMemoryComponentRepository (para testing)
 * - FileSystemComponentRepository (futuro: archivos JSON)
 *
 * PRINCIPIOS:
 * - Métodos retornan entidades de dominio (Component)
 * - Parámetros son Value Objects o primitivos
 * - Excepciones son de dominio
 * - Sin conocimiento de WordPress/BD
 *
 * USO:
 * ```php
 * // En Application Layer
 * class SaveComponentUseCase {
 *     public function __construct(
 *         private ComponentRepositoryInterface $repository
 *     ) {}
 *
 *     public function execute(SaveComponentRequest $request): void {
 *         $component = new Component(...);
 *         $this->repository->save($component);
 *     }
 * }
 * ```
 *
 * @package ROITheme\Shared\Domain\Contracts
 */
interface ComponentRepositoryInterface
{
    /**
     * Guardar o actualizar un componente
     *
     * Si el componente ya existe (por nombre), se actualiza.
     * Si no existe, se crea.
     *
     * @param Component $component Componente a guardar
     * @return Component Componente guardado (con timestamps actualizados)
     */
    public function save(Component $component): Component;

    /**
     * Buscar componente por nombre
     *
     * @param ComponentName $name Nombre del componente
     * @return Component|null Componente encontrado o null
     */
    public function findByName(ComponentName $name): ?Component;

    /**
     * Obtener componente por nombre (lanza excepción si no existe)
     *
     * @param ComponentName $name
     * @return Component
     * @throws ComponentNotFoundException
     */
    public function getByName(ComponentName $name): Component;

    /**
     * Obtener todos los componentes
     *
     * @return Component[] Array de componentes
     */
    public function findAll(): array;

    /**
     * Obtener componentes habilitados
     *
     * @return Component[] Array de componentes habilitados
     */
    public function findEnabled(): array;

    /**
     * Verificar si existe un componente con el nombre dado
     *
     * @param ComponentName $name
     * @return bool
     */
    public function exists(ComponentName $name): bool;

    /**
     * Eliminar un componente
     *
     * @param ComponentName $name Nombre del componente a eliminar
     * @return bool True si se eliminó, false si no existía
     */
    public function delete(ComponentName $name): bool;

    /**
     * Obtener cantidad total de componentes
     *
     * @return int
     */
    public function count(): int;

    /**
     * Obtener componentes por grupo de configuración
     *
     * Ejemplo: Obtener todos los componentes que tienen configuración de 'content'
     *
     * @param string $group Grupo de configuración (visibility, content, styles, general)
     * @return Component[]
     */
    public function findByConfigGroup(string $group): array;
}
