<?php

namespace NeurogenesisTheme\Helpers;

defined('ABSPATH') || exit;

/**
 * Single theme-slug-prefixed options array (theme review §12).
 *
 * All theme settings live under `thinko_options`. Legacy flat option keys are
 * migrated once and then deleted.
 */
final class ThemeOptions
{
    public const OPTION_NAME = 'thinko_options';

    public const CONTENT_IMPORTED         = 'content_imported';
    public const INSTALLED_ON             = 'installed_on';
    public const QUICK_SETUP_STARTED_AT   = 'quick_setup_started_at';
    public const LAYOUT_THEME_FILES       = 'layout_theme_files';
    public const CONTENT_IMPORT_DONE      = 'content_import_done';
    public const LAYOUT_SUPPORTING        = 'layout_supporting';
    public const ONBOARDING_DISMISSED     = 'onboarding_dismissed';
    public const ONBOARDING_SNOOZED_UNTIL = 'onboarding_snoozed_until';
    public const THEME_CUSTOMIZED         = 'theme_customized';

    /** @var bool */
    private static $migrated = false;

    /**
     * @param mixed $default
     * @return mixed
     */
    public static function get(string $key, $default = null)
    {
        self::migrate_legacy();
        $all = self::raw();

        return array_key_exists($key, $all) ? $all[$key] : $default;
    }

    /**
     * @param mixed $value
     */
    public static function set(string $key, $value): void
    {
        self::set_many([$key => $value]);
    }

    /**
     * @param array<string, mixed> $values
     */
    public static function set_many(array $values): void
    {
        if ([] === $values) {
            return;
        }

        self::migrate_legacy();
        $all = self::raw();
        foreach ($values as $key => $value) {
            if (!is_string($key) || '' === $key) {
                continue;
            }
            $all[$key] = $value;
        }
        update_option(self::OPTION_NAME, $all, false);
    }

    public static function delete(string $key): void
    {
        self::delete_many([$key]);
    }

    /**
     * @param list<string> $keys
     */
    public static function delete_many(array $keys): void
    {
        self::migrate_legacy();
        $all     = self::raw();
        $changed = false;

        foreach ($keys as $key) {
            if (!is_string($key) || !array_key_exists($key, $all)) {
                continue;
            }
            unset($all[$key]);
            $changed = true;
        }

        if ($changed) {
            update_option(self::OPTION_NAME, $all, false);
        }
    }

    /**
     * @return array<string, mixed>
     */
    public static function all(): array
    {
        self::migrate_legacy();

        return self::raw();
    }

    /**
     * Copy legacy flat options into `thinko_options`, then delete them.
     */
    public static function migrate_legacy(): void
    {
        if (self::$migrated) {
            return;
        }
        self::$migrated = true;

        $current = self::raw();
        $changed = false;
        $stylesheet = (string) get_stylesheet();

        $scalar_map = [
            'NeurogenesisThemeContentImported'                              => self::CONTENT_IMPORTED,
            'NeurogenesisThemeInstalledOn'                                  => self::INSTALLED_ON,
            'neurogenesis_theme_quick_setup_started_at'                     => self::QUICK_SETUP_STARTED_AT,
            'neurogenesis_theme_theme_customized'                           => self::THEME_CUSTOMIZED,
            'neurogenesis_theme_' . $stylesheet . '_layout_theme_files_v1'   => self::LAYOUT_THEME_FILES,
            'neurogenesis_theme_' . $stylesheet . '_theme_content_import_v1' => self::CONTENT_IMPORT_DONE,
            'neurogenesis_theme_' . $stylesheet . '_layout_supporting_v1'    => self::LAYOUT_SUPPORTING,
        ];

        foreach ($scalar_map as $legacy_key => $new_key) {
            $value = self::read_legacy_option($legacy_key);
            if (null === $value) {
                continue;
            }

            if (!array_key_exists($new_key, $current)) {
                $current[$new_key] = $value;
                $changed           = true;
            }

            delete_option($legacy_key);
        }

        $notices = self::read_legacy_option('neurogenesis_theme_admin_notices');
        if (is_array($notices)) {
            if (!array_key_exists(self::ONBOARDING_DISMISSED, $current) && array_key_exists('onboarding_dismissed', $notices)) {
                $current[self::ONBOARDING_DISMISSED] = !empty($notices['onboarding_dismissed']);
                $changed                             = true;
            }
            if (!array_key_exists(self::ONBOARDING_SNOOZED_UNTIL, $current) && array_key_exists('onboarding_snoozed_until', $notices)) {
                $current[self::ONBOARDING_SNOOZED_UNTIL] = (int) $notices['onboarding_snoozed_until'];
                $changed                                 = true;
            }
            delete_option('neurogenesis_theme_admin_notices');
        }

        if ($changed) {
            update_option(self::OPTION_NAME, $current, false);
        }
    }

    /**
     * @return array<string, mixed>
     */
    private static function raw(): array
    {
        $raw = get_option(self::OPTION_NAME, []);

        return is_array($raw) ? $raw : [];
    }

    /**
     * @return mixed|null Null when the option does not exist.
     */
    private static function read_legacy_option(string $key)
    {
        $sentinel = new \stdClass();
        $value    = get_option($key, $sentinel);

        return $value === $sentinel ? null : $value;
    }
}
