<?php
declare(strict_types=1);

namespace ROITheme\Admin\Shared\Infrastructure\Ui;

use ROITheme\Admin\Infrastructure\Ui\AdminDashboardRenderer;

/**
 * Componente UI parcial reutilizable para reglas de exclusion
 *
 * Genera el HTML para la seccion de exclusiones en FormBuilders.
 * Debe ser incluido despues de la seccion de visibilidad por tipo de pagina.
 *
 * Uso en FormBuilder:
 * ```php
 * $exclusionPartial = new ExclusionFormPartial($this->renderer);
 * $html .= $exclusionPartial->render($componentId, 'prefijo');
 * ```
 *
 * @package ROITheme\Admin\Shared\Infrastructure\Ui
 */
final class ExclusionFormPartial
{
    private const GROUP_NAME = '_exclusions';

    public function __construct(
        private readonly AdminDashboardRenderer $renderer
    ) {}

    /**
     * Renderiza la seccion de exclusiones
     *
     * @param string $componentId ID del componente (kebab-case)
     * @param string $prefix Prefijo para IDs de campos (ej: 'cta' genera 'ctaExclusionsEnabled')
     * @return string HTML de la seccion
     */
    public function render(string $componentId, string $prefix): string
    {
        $html = '';

        $html .= $this->buildExclusionHeader();
        $html .= $this->buildExclusionToggle($componentId, $prefix);
        $html .= $this->buildExclusionRules($componentId, $prefix);

        return $html;
    }

    private function buildExclusionHeader(): string
    {
        $html = '<hr class="my-3">';
        $html .= '<p class="small fw-semibold mb-2">';
        $html .= '    <i class="bi bi-funnel me-1" style="color: #FF8600;"></i>';
        $html .= '    Reglas de exclusion avanzadas';
        $html .= '</p>';
        $html .= '<p class="small text-muted mb-2">';
        $html .= '    Excluir este componente de categorias, posts o URLs especificos.';
        $html .= '</p>';

        return $html;
    }

    private function buildExclusionToggle(string $componentId, string $prefix): string
    {
        $enabled = $this->renderer->getFieldValue(
            $componentId,
            self::GROUP_NAME,
            'exclusions_enabled',
            false
        );
        $checked = $this->toBool($enabled);

        $id = $prefix . 'ExclusionsEnabled';

        $html = '<div class="mb-3">';
        $html .= '    <div class="form-check form-switch">';
        $html .= sprintf(
            '        <input class="form-check-input" type="checkbox" id="%s" %s>',
            esc_attr($id),
            $checked ? 'checked' : ''
        );
        $html .= sprintf(
            '        <label class="form-check-label small" for="%s">',
            esc_attr($id)
        );
        $html .= '            <i class="bi bi-filter-circle me-1" style="color: #FF8600;"></i>';
        $html .= '            <strong>Activar reglas de exclusion</strong>';
        $html .= '        </label>';
        $html .= '    </div>';
        $html .= '</div>';

        return $html;
    }

    private function buildExclusionRules(string $componentId, string $prefix): string
    {
        $enabled = $this->renderer->getFieldValue(
            $componentId,
            self::GROUP_NAME,
            'exclusions_enabled',
            false
        );
        $display = $this->toBool($enabled) ? 'block' : 'none';

        $html = sprintf(
            '<div id="%sExclusionRules" style="display: %s;">',
            esc_attr($prefix),
            $display
        );

        $html .= $this->buildCategoryField($componentId, $prefix);
        $html .= $this->buildPostIdsField($componentId, $prefix);
        $html .= $this->buildUrlPatternsField($componentId, $prefix);

        $html .= '</div>';

        return $html;
    }

    private function buildCategoryField(string $componentId, string $prefix): string
    {
        $value = $this->renderer->getFieldValue(
            $componentId,
            self::GROUP_NAME,
            'exclude_categories',
            '[]'
        );
        $categories = $this->jsonToCommaList($value);

        $id = $prefix . 'ExcludeCategories';

        $html = '<div class="mb-3">';
        $html .= sprintf(
            '    <label for="%s" class="form-label small mb-1 fw-semibold">',
            esc_attr($id)
        );
        $html .= '        <i class="bi bi-folder me-1" style="color: #FF8600;"></i>';
        $html .= '        Excluir en categorias';
        $html .= '    </label>';
        $html .= sprintf(
            '    <input type="text" id="%s" class="form-control form-control-sm" value="%s" placeholder="noticias, eventos, tutoriales">',
            esc_attr($id),
            esc_attr($categories)
        );
        $html .= '    <small class="text-muted">Slugs de categorias separados por comas</small>';
        $html .= '</div>';

        return $html;
    }

    private function buildPostIdsField(string $componentId, string $prefix): string
    {
        $value = $this->renderer->getFieldValue(
            $componentId,
            self::GROUP_NAME,
            'exclude_post_ids',
            '[]'
        );
        $postIds = $this->jsonToCommaList($value);

        $id = $prefix . 'ExcludePostIds';

        $html = '<div class="mb-3">';
        $html .= sprintf(
            '    <label for="%s" class="form-label small mb-1 fw-semibold">',
            esc_attr($id)
        );
        $html .= '        <i class="bi bi-hash me-1" style="color: #FF8600;"></i>';
        $html .= '        Excluir en posts/paginas';
        $html .= '    </label>';
        $html .= sprintf(
            '    <input type="text" id="%s" class="form-control form-control-sm" value="%s" placeholder="123, 456, 789">',
            esc_attr($id),
            esc_attr($postIds)
        );
        $html .= '    <small class="text-muted">IDs de posts o paginas separados por comas</small>';
        $html .= '</div>';

        return $html;
    }

    private function buildUrlPatternsField(string $componentId, string $prefix): string
    {
        $value = $this->renderer->getFieldValue(
            $componentId,
            self::GROUP_NAME,
            'exclude_url_patterns',
            '[]'
        );
        $patterns = $this->jsonToLineList($value);

        $id = $prefix . 'ExcludeUrlPatterns';

        $html = '<div class="mb-0">';
        $html .= sprintf(
            '    <label for="%s" class="form-label small mb-1 fw-semibold">',
            esc_attr($id)
        );
        $html .= '        <i class="bi bi-link-45deg me-1" style="color: #FF8600;"></i>';
        $html .= '        Excluir por patrones URL';
        $html .= '    </label>';
        $html .= sprintf(
            '    <textarea id="%s" class="form-control form-control-sm" rows="3" placeholder="/privado/&#10;/landing-especial/&#10;/^\/categoria\/\d+$/">%s</textarea>',
            esc_attr($id),
            esc_textarea($patterns)
        );
        $html .= '    <small class="text-muted">Un patron por linea. Soporta texto simple o regex (ej: /^\/blog\/\d+$/)</small>';
        $html .= '</div>';

        return $html;
    }

    /**
     * Convierte JSON array o array a lista separada por comas
     *
     * @param string|array $value Valor desde BD (puede ser JSON string o array ya deserializado)
     */
    private function jsonToCommaList(string|array $value): string
    {
        // Si ya es array, usarlo directamente
        if (is_array($value)) {
            return empty($value) ? '' : implode(', ', $value);
        }

        // Si es string, intentar decodificar JSON
        $decoded = json_decode($value, true);

        if (!is_array($decoded) || empty($decoded)) {
            return '';
        }

        return implode(', ', $decoded);
    }

    /**
     * Convierte JSON array o array a lista separada por lineas
     *
     * @param string|array $value Valor desde BD (puede ser JSON string o array ya deserializado)
     */
    private function jsonToLineList(string|array $value): string
    {
        // Si ya es array, usarlo directamente
        if (is_array($value)) {
            return empty($value) ? '' : implode("\n", $value);
        }

        // Si es string, intentar decodificar JSON
        $decoded = json_decode($value, true);

        if (!is_array($decoded) || empty($decoded)) {
            return '';
        }

        return implode("\n", $decoded);
    }

    private function toBool(mixed $value): bool
    {
        return $value === true || $value === '1' || $value === 1;
    }
}
