<?php
declare(strict_types=1);

namespace ROITheme\Shared\Infrastructure\Persistence\WordPress;

use ROITheme\Shared\Domain\Contracts\ExclusionRepositoryInterface;
use ROITheme\Shared\Domain\ValueObjects\ExclusionRuleSet;
use ROITheme\Shared\Domain\ValueObjects\CategoryExclusion;
use ROITheme\Shared\Domain\ValueObjects\PostIdExclusion;
use ROITheme\Shared\Domain\ValueObjects\UrlPatternExclusion;
use ROITheme\Shared\Domain\Constants\ExclusionDefaults;

/**
 * Implementacion WordPress del repositorio de exclusiones
 *
 * Almacena exclusiones en wp_roi_theme_component_settings
 * con group_name = '_exclusions'
 *
 * @package ROITheme\Shared\Infrastructure\Persistence\WordPress
 */
final class WordPressExclusionRepository implements ExclusionRepositoryInterface
{
    private const TABLE_SUFFIX = 'roi_theme_component_settings';

    public function __construct(
        private readonly \wpdb $wpdb
    ) {}

    public function getExclusions(string $componentName): ExclusionRuleSet
    {
        $table = $this->wpdb->prefix . self::TABLE_SUFFIX;
        $groupName = ExclusionDefaults::GROUP_NAME;

        $results = $this->wpdb->get_results(
            $this->wpdb->prepare(
                "SELECT attribute_name, attribute_value
                 FROM {$table}
                 WHERE component_name = %s
                 AND group_name = %s",
                $componentName,
                $groupName
            ),
            ARRAY_A
        );

        if (empty($results)) {
            return ExclusionRuleSet::empty($componentName);
        }

        $data = [];
        foreach ($results as $row) {
            $data[$row['attribute_name']] = $row['attribute_value'];
        }

        return $this->hydrateExclusions($componentName, $data);
    }

    public function saveExclusions(ExclusionRuleSet $exclusions): void
    {
        $componentName = $exclusions->getComponentName();

        $data = [
            'exclusions_enabled' => $exclusions->isEnabled() ? '1' : '0',
            'exclude_categories' => $exclusions->getCategoryExclusion()->serialize(),
            'exclude_post_ids' => $exclusions->getPostIdExclusion()->serialize(),
            'exclude_url_patterns' => $exclusions->getUrlPatternExclusion()->serialize(),
        ];

        foreach ($data as $field => $value) {
            $this->upsertField($componentName, $field, $value);
        }
    }

    public function hasExclusions(string $componentName): bool
    {
        $table = $this->wpdb->prefix . self::TABLE_SUFFIX;
        $groupName = ExclusionDefaults::GROUP_NAME;

        $count = $this->wpdb->get_var($this->wpdb->prepare(
            "SELECT COUNT(*) FROM {$table}
             WHERE component_name = %s
             AND group_name = %s",
            $componentName,
            $groupName
        ));

        return (int) $count > 0;
    }

    private function hydrateExclusions(string $componentName, array $data): ExclusionRuleSet
    {
        $enabled = ($data['exclusions_enabled'] ?? '0') === '1';

        $categoryExclusion = CategoryExclusion::fromJson($data['exclude_categories'] ?? '[]');
        $postIdExclusion = PostIdExclusion::fromJson($data['exclude_post_ids'] ?? '[]');
        $urlPatternExclusion = UrlPatternExclusion::fromJson($data['exclude_url_patterns'] ?? '[]');

        return new ExclusionRuleSet(
            $componentName,
            $enabled,
            $categoryExclusion,
            $postIdExclusion,
            $urlPatternExclusion
        );
    }

    private function upsertField(string $componentName, string $field, string $value): void
    {
        $table = $this->wpdb->prefix . self::TABLE_SUFFIX;
        $groupName = ExclusionDefaults::GROUP_NAME;

        $exists = $this->wpdb->get_var($this->wpdb->prepare(
            "SELECT COUNT(*) FROM {$table}
             WHERE component_name = %s
             AND group_name = %s
             AND attribute_name = %s",
            $componentName,
            $groupName,
            $field
        ));

        if ($exists) {
            $this->wpdb->update(
                $table,
                [
                    'attribute_value' => $value,
                    'updated_at' => current_time('mysql'),
                ],
                [
                    'component_name' => $componentName,
                    'group_name' => $groupName,
                    'attribute_name' => $field,
                ]
            );
        } else {
            $this->wpdb->insert($table, [
                'component_name' => $componentName,
                'group_name' => $groupName,
                'attribute_name' => $field,
                'attribute_value' => $value,
                'is_editable' => 1,
                'created_at' => current_time('mysql'),
                'updated_at' => current_time('mysql'),
            ]);
        }
    }
}
