<?php

namespace WPSN\Modules\ImportExport;

defined('ABSPATH') || exit;

final class ImportAssistFilterPresetRepository
{
    private const OPTION_NAME = 'wpsn_import_assist_filter_presets';
    private const DEFAULT_OPTION_NAME = 'wpsn_import_assist_filter_default';
    private const MAX_PRESETS = 12;

    /**
     * @return array<string,array{slug:string,label:string,status:string,priority:string,focus:string,created_at:string,updated_at:string}>
     */
    public function all(): array
    {
        $raw = get_option(self::OPTION_NAME, []);
        if (!is_array($raw)) {
            return [];
        }

        $out = [];
        foreach ($raw as $slug => $row) {
            $normalized = $this->normalizeRow($slug, $row);
            if ($normalized === null) {
                continue;
            }
            $out[$normalized['slug']] = $normalized;
        }

        uasort($out, static function (array $a, array $b): int {
            return strcmp((string) ($a['label'] ?? ''), (string) ($b['label'] ?? ''));
        });

        return $out;
    }

    /**
     * @return array{slug:string,label:string,status:string,priority:string,focus:string,created_at:string,updated_at:string}|null
     */
    public function get(string $slug): ?array
    {
        $slug = $this->normalizeSlug($slug);
        if ($slug === '') {
            return null;
        }

        $all = $this->all();
        return $all[$slug] ?? null;
    }

    public function save(string $label, string $status, string $priority, string $focus = 'all', string $preferredSlug = ''): string
    {
        $label = $this->normalizeLabel($label);
        $status = $this->normalizeStatus($status);
        $priority = $this->normalizePriority($priority);
        $focus = $this->normalizeFocus($focus);
        if ($label === '') {
            return '';
        }

        $all = $this->all();
        $slug = $this->normalizeSlug($preferredSlug);
        if ($slug === '') {
            $slug = $this->slugFromLabel($label);
        }
        $slug = $this->ensureUniqueSlug($slug, array_keys($all));

        $now = gmdate('Y-m-d H:i:s');
        $existing = $all[$slug] ?? null;
        $all[$slug] = [
            'slug' => $slug,
            'label' => $label,
            'status' => $status,
            'priority' => $priority,
            'focus' => $focus,
            'created_at' => is_array($existing) && !empty($existing['created_at']) ? (string) $existing['created_at'] : $now,
            'updated_at' => $now,
        ];

        if (count($all) > self::MAX_PRESETS) {
            uasort($all, static function (array $a, array $b): int {
                return strcmp((string) ($a['updated_at'] ?? ''), (string) ($b['updated_at'] ?? ''));
            });
            while (count($all) > self::MAX_PRESETS) {
                array_shift($all);
            }
        }

        update_option(self::OPTION_NAME, $all, false);
        return $slug;
    }

    public function delete(string $slug): bool
    {
        $slug = $this->normalizeSlug($slug);
        if ($slug === '') {
            return false;
        }

        $all = $this->all();
        if (!isset($all[$slug])) {
            return false;
        }

        unset($all[$slug]);
        update_option(self::OPTION_NAME, $all, false);
        if ($this->defaultSlug() === $slug) {
            $this->clearDefault();
        }

        return true;
    }

    public function defaultSlug(): string
    {
        $slug = get_option(self::DEFAULT_OPTION_NAME, '');
        return is_string($slug) ? $this->normalizeSlug($slug) : '';
    }

    public function setDefault(string $slug): bool
    {
        $slug = $this->normalizeSlug($slug);
        if ($slug === '') {
            return false;
        }

        return update_option(self::DEFAULT_OPTION_NAME, $slug, false);
    }

    public function clearDefault(): bool
    {
        return delete_option(self::DEFAULT_OPTION_NAME);
    }

    private function normalizeSlug(string $slug): string
    {
        $slug = strtolower(trim($slug));
        $slug = preg_replace('/[^a-z0-9_-]+/', '-', $slug) ?? $slug;
        $slug = trim($slug, '-_');
        return $slug;
    }

    private function slugFromLabel(string $label): string
    {
        $slug = strtolower($label);
        $slug = preg_replace('/[^a-z0-9]+/', '-', $slug) ?? $slug;
        $slug = trim($slug, '-');
        return $slug !== '' ? $slug : 'preset';
    }

    /**
     * @param array<int,string> $existing
     */
    private function ensureUniqueSlug(string $slug, array $existing): string
    {
        $slug = $this->normalizeSlug($slug);
        if ($slug === '') {
            $slug = 'preset';
        }

        $lookup = [];
        foreach ($existing as $item) {
            $item = $this->normalizeSlug((string) $item);
            if ($item !== '') {
                $lookup[$item] = true;
            }
        }

        if (!isset($lookup[$slug])) {
            return $slug;
        }

        $base = $slug;
        $i = 2;
        while (isset($lookup[$base . '-' . $i])) {
            $i++;
        }
        return $base . '-' . $i;
    }

    private function normalizeLabel(string $label): string
    {
        $label = sanitize_text_field($label);
        $label = trim($label);
        if ($label === '') {
            return '';
        }
        return function_exists('mb_substr') ? (string) mb_substr($label, 0, 60, 'UTF-8') : substr($label, 0, 60);
    }

    private function normalizeStatus(string $status): string
    {
        $status = sanitize_key($status);
        return in_array($status, ['all', 'open', 'checked'], true) ? $status : 'all';
    }

    private function normalizePriority(string $priority): string
    {
        $priority = sanitize_key($priority);
        return in_array($priority, ['all', 'high', 'medium', 'low'], true) ? $priority : 'all';
    }

    private function normalizeFocus(string $focus): string
    {
        $focus = sanitize_key($focus);
        return in_array($focus, ['all', 'technical', 'schema_content', 'redirects_links', 'presentation', 'reports'], true) ? $focus : 'all';
    }

    /**
     * @param mixed $row
     * @return array{slug:string,label:string,status:string,priority:string,focus:string,created_at:string,updated_at:string}|null
     */
    private function normalizeRow(string $slug, $row): ?array
    {
        if (!is_array($row)) {
            return null;
        }

        $slug = $this->normalizeSlug($slug !== '' ? $slug : (string) ($row['slug'] ?? ''));
        $label = $this->normalizeLabel((string) ($row['label'] ?? ''));
        if ($slug === '' || $label === '') {
            return null;
        }

        return [
            'slug' => $slug,
            'label' => $label,
            'status' => $this->normalizeStatus((string) ($row['status'] ?? 'all')),
            'priority' => $this->normalizePriority((string) ($row['priority'] ?? 'all')),
            'focus' => $this->normalizeFocus((string) ($row['focus'] ?? 'all')),
            'created_at' => sanitize_text_field((string) ($row['created_at'] ?? '')),
            'updated_at' => sanitize_text_field((string) ($row['updated_at'] ?? '')),
        ];
    }
}
