<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Support;

if (! defined('ABSPATH')) {
    exit;
}

final class NetworkSettings
{
    public const OPTION_KEY = 'h4bs_network_settings';
    public const PROVISION_STATE_OPTION = 'h4bs_network_provision_state';
    public const PROVISION_HOOK = 'h4bs_multisite_provision_batch';

    /**
     * @return array<string, array{label: string, type: string, description: string}>
     */
    public static function policyCatalog(): array
    {
        return [
            'brand_name' => [
                'label' => __('Brand name', 'help4-builder-suite'),
                'type' => 'text',
                'description' => __('Default organization name used by schema and social previews.', 'help4-builder-suite'),
            ],
            'support_url' => [
                'label' => __('Support URL', 'help4-builder-suite'),
                'type' => 'url',
                'description' => __('Shared support or contact destination.', 'help4-builder-suite'),
            ],
            'default_social_image_url' => [
                'label' => __('Default social image URL', 'help4-builder-suite'),
                'type' => 'url',
                'description' => __('Fallback image when a site or item has no dedicated social image.', 'help4-builder-suite'),
            ],
            'twitter_site' => [
                'label' => __('X/Twitter account', 'help4-builder-suite'),
                'type' => 'twitter',
                'description' => __('Shared publisher account, including the leading @.', 'help4-builder-suite'),
            ],
            'business_phone' => [
                'label' => __('Business phone', 'help4-builder-suite'),
                'type' => 'text',
                'description' => __('Fallback organization telephone for structured data.', 'help4-builder-suite'),
            ],
            'same_as_urls' => [
                'label' => __('Organization profile URLs', 'help4-builder-suite'),
                'type' => 'urls',
                'description' => __('Verified organization profiles used by sameAs schema.', 'help4-builder-suite'),
            ],
            'indexnow_enabled' => [
                'label' => __('Enable IndexNow', 'help4-builder-suite'),
                'type' => 'bool',
                'description' => __('Each site receives its own generated key; keys are never shared network-wide.', 'help4-builder-suite'),
            ],
            'seo_video_sitemap_enabled' => [
                'label' => __('Video sitemap', 'help4-builder-suite'),
                'type' => 'bool',
                'description' => __('Expose a video sitemap on sites that publish indexable video content.', 'help4-builder-suite'),
            ],
            'seo_news_sitemap_enabled' => [
                'label' => __('News sitemap', 'help4-builder-suite'),
                'type' => 'bool',
                'description' => __('Expose a recent-news sitemap only where the network publishes qualifying news.', 'help4-builder-suite'),
            ],
            'seo_rss_before_content' => [
                'label' => __('RSS content prefix', 'help4-builder-suite'),
                'type' => 'textarea',
                'description' => __('Attribution text placed before feed content.', 'help4-builder-suite'),
            ],
            'seo_rss_after_content' => [
                'label' => __('RSS content suffix', 'help4-builder-suite'),
                'type' => 'textarea',
                'description' => __('Attribution text placed after feed content.', 'help4-builder-suite'),
            ],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public static function defaults(): array
    {
        $siteDefaults = Settings::defaults();
        $values = [];
        foreach (array_keys(self::policyCatalog()) as $key) {
            $values[$key] = $siteDefaults[$key] ?? '';
        }

        return [
            'schema_version' => 1,
            'provision_new_sites' => '1',
            'default_business_profile' => 'business',
            'default_values' => $values,
            'enforced_keys' => [],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public static function all(): array
    {
        if (! is_multisite()) {
            return self::defaults();
        }

        $saved = get_site_option(self::OPTION_KEY, []);
        $saved = is_array($saved) ? $saved : [];
        return self::sanitize(array_replace_recursive(self::defaults(), $saved));
    }

    /**
     * @param mixed $raw
     * @return array<string, mixed>
     */
    public static function sanitize($raw): array
    {
        $raw = is_array($raw) ? $raw : [];
        $defaults = self::defaults();
        $catalog = self::policyCatalog();
        $rawValues = is_array($raw['default_values'] ?? null) ? $raw['default_values'] : [];
        $values = [];

        foreach ($catalog as $key => $definition) {
            $value = $rawValues[$key] ?? $defaults['default_values'][$key] ?? '';
            switch ($definition['type']) {
                case 'bool':
                    $values[$key] = rest_sanitize_boolean($value) ? '1' : '0';
                    break;
                case 'url':
                    $values[$key] = esc_url_raw((string) $value, ['http', 'https']);
                    break;
                case 'urls':
                    $rows = is_array($value) ? $value : (preg_split('/\r\n|\r|\n/', (string) $value) ?: []);
                    $urls = [];
                    foreach ($rows as $url) {
                        $url = esc_url_raw(trim((string) $url), ['http', 'https']);
                        if ($url !== '') {
                            $urls[] = $url;
                        }
                    }
                    $values[$key] = array_slice(array_values(array_unique($urls)), 0, 30);
                    break;
                case 'twitter':
                    $handle = trim((string) $value);
                    if (filter_var($handle, FILTER_VALIDATE_URL)) {
                        $handle = basename(trim((string) wp_parse_url($handle, PHP_URL_PATH), '/'));
                    }
                    $handle = (string) preg_replace('/[^A-Za-z0-9_]/', '', ltrim($handle, '@'));
                    $values[$key] = $handle !== '' ? '@' . substr($handle, 0, 15) : '';
                    break;
                case 'textarea':
                    $values[$key] = sanitize_textarea_field((string) $value);
                    break;
                default:
                    $values[$key] = sanitize_text_field((string) $value);
                    break;
            }
        }

        $enforced = [];
        foreach ((array) ($raw['enforced_keys'] ?? []) as $key) {
            $key = sanitize_key((string) $key);
            if (isset($catalog[$key])) {
                $enforced[] = $key;
            }
        }

        $profile = sanitize_key((string) ($raw['default_business_profile'] ?? 'business'));
        if (! BusinessProfileDefaults::profile($profile)) {
            $profile = 'business';
        }

        return [
            'schema_version' => 1,
            'provision_new_sites' => rest_sanitize_boolean($raw['provision_new_sites'] ?? '0') ? '1' : '0',
            'default_business_profile' => $profile,
            'default_values' => $values,
            'enforced_keys' => array_values(array_unique($enforced)),
        ];
    }

    /**
     * @param array<string, mixed> $settings
     * @return array<string, mixed>
     */
    public static function applyEnforcedValues(array $settings): array
    {
        if (! is_multisite()) {
            return $settings;
        }

        $network = self::all();
        $values = is_array($network['default_values'] ?? null) ? $network['default_values'] : [];
        foreach ((array) ($network['enforced_keys'] ?? []) as $key) {
            $key = sanitize_key((string) $key);
            if ($key !== '' && array_key_exists($key, $values)) {
                $settings[$key] = $values[$key];
            }
        }

        return (array) apply_filters('h4bs_network_effective_settings', $settings, $network, get_current_blog_id());
    }

    /**
     * @return array{updated: array<int, string>, preserved: array<int, string>, generated_indexnow_key: bool, profile: string}
     */
    public static function applyDefaultsToCurrentSite(bool $overwrite = false, bool $newSite = false): array
    {
        $network = self::all();
        $values = is_array($network['default_values'] ?? null) ? $network['default_values'] : [];
        $saved = get_option(Settings::OPTION_KEY, []);
        $saved = is_array($saved) ? $saved : [];
        $updated = [];
        $preserved = [];
        $profile = sanitize_key((string) ($network['default_business_profile'] ?? 'business'));

        if ($newSite) {
            BusinessProfileDefaults::rememberProfile($profile);
            $saved = array_replace($saved, BusinessProfileDefaults::settingsDefaults(Settings::defaults(), $profile));
        }

        foreach ($values as $key => $value) {
            $key = sanitize_key((string) $key);
            if (! isset(self::policyCatalog()[$key])) {
                continue;
            }
            $missing = ! array_key_exists($key, $saved);
            $empty = self::isEmptyValue($saved[$key] ?? null);
            if ($newSite || $overwrite || $missing || $empty) {
                $saved[$key] = $value;
                $updated[] = $key;
            } else {
                $preserved[] = $key;
            }
        }

        $generatedKey = false;
        if (
            rest_sanitize_boolean($saved['indexnow_enabled'] ?? '0')
            && strlen((string) preg_replace('/[^A-Za-z0-9-]/', '', (string) ($saved['indexnow_key'] ?? ''))) < 8
        ) {
            $saved['indexnow_key'] = wp_generate_password(32, false, false);
            $updated[] = 'indexnow_key';
            $generatedKey = true;
        }

        update_option(Settings::OPTION_KEY, $saved, false);
        BusinessProfileDefaults::markUserOwnedSettings($updated);

        do_action('h4bs_network_defaults_applied', get_current_blog_id(), $updated, $preserved, $overwrite, $newSite);

        return [
            'updated' => array_values(array_unique($updated)),
            'preserved' => array_values(array_unique($preserved)),
            'generated_indexnow_key' => $generatedKey,
            'profile' => $profile,
        ];
    }

    /**
     * @return array<int, string>
     */
    public static function enforcedKeys(): array
    {
        return is_multisite() ? array_values((array) (self::all()['enforced_keys'] ?? [])) : [];
    }

    private static function isEmptyValue(mixed $value): bool
    {
        if (is_array($value)) {
            return $value === [];
        }

        return trim((string) $value) === '';
    }
}
