<?php
/**
 * Shared PEWIT Labs AI credentials hub.
 *
 * Copied identically into each PEWIT AI plugin (guarded by class_exists).
 * When 2+ registered suite plugins are active, one elected owner shows a
 * top-level "PEWIT Labs" admin page for provider / API key / model / context.
 * Single-plugin installs keep credentials in that plugin's own settings.
 */
if (!defined('ABSPATH')) {
    exit;
}

if (class_exists('Pewit_Labs_Hub')) {
    return;
}

class Pewit_Labs_Hub {

    const OPTION = 'pewit_labs_ai';
    const PAGE   = 'pewit-labs-ai';
    const NONCE  = 'pewit_labs_ai';

    /** @var array<string,array{label:string,text_domain:string,priority:int,llm_class:string,seed_callback:callable|null}> */
    private static $registry = [];

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

    /**
     * @param string               $slug Plugin directory slug.
     * @param array<string,mixed>  $args label, text_domain, priority, llm_class, seed_callback.
     */
    public static function register($slug, array $args = []) {
        $slug = sanitize_key($slug);
        if ($slug === '') {
            return;
        }
        self::$registry[$slug] = [
            'label'         => (string) ($args['label'] ?? $slug),
            'text_domain'   => (string) ($args['text_domain'] ?? $slug),
            'priority'      => (int) ($args['priority'] ?? 50),
            'llm_class'     => (string) ($args['llm_class'] ?? ''),
            'seed_callback' => isset($args['seed_callback']) && is_callable($args['seed_callback']) ? $args['seed_callback'] : null,
        ];
    }

    public static function boot() {
        if (self::$booted) {
            return;
        }
        self::$booted = true;
        add_action('admin_menu', [__CLASS__, 'maybe_register_menu'], 9);
        add_action('admin_enqueue_scripts', [__CLASS__, 'assets']);
        add_action('wp_ajax_pewit_labs_save_ai', [__CLASS__, 'ajax_save']);
        add_action('wp_ajax_pewit_labs_test_ai', [__CLASS__, 'ajax_test']);
        add_action('admin_init', [__CLASS__, 'maybe_seed'], 20);
    }

    /**
     * @return array<string,array{label:string,text_domain:string,priority:int,llm_class:string,seed_callback:callable|null}>
     */
    public static function active_plugins() {
        $active = self::$registry;
        uasort($active, static function ($a, $b) {
            if ($a['priority'] === $b['priority']) {
                return strcmp((string) ($a['label'] ?? ''), (string) ($b['label'] ?? ''));
            }
            return ($a['priority'] < $b['priority']) ? -1 : 1;
        });
        return $active;
    }

    public static function should_show_hub() {
        return count(self::active_plugins()) >= 2;
    }

    /**
     * @return string|null Elected owner slug.
     */
    public static function elected_owner() {
        $active = self::active_plugins();
        if (!$active) {
            return null;
        }
        return (string) array_key_first($active);
    }

    public static function is_owner($slug) {
        return self::elected_owner() === sanitize_key($slug);
    }

    public static function admin_url() {
        return admin_url('admin.php?page=' . self::PAGE);
    }

    public static function default_settings() {
        return [
            'api_key'          => '',
            'api_key_verified' => 0,
            'provider'         => 'openai',
            'model'            => 'gpt-4o-mini',
            'global_context'   => '',
        ];
    }

    public static function get_settings() {
        return wp_parse_args(get_option(self::OPTION, []), self::default_settings());
    }

    public static function update_settings(array $settings) {
        update_option(self::OPTION, wp_parse_args($settings, self::default_settings()), false);
    }

    /**
     * Shared credentials when hub mode is on and a verified key exists.
     *
     * @return array{api_key:string,provider:string,model:string,global_context:string}|null
     */
    public static function credentials() {
        if (!self::should_show_hub()) {
            return null;
        }
        $s = self::get_settings();
        if (empty($s['api_key']) || empty($s['api_key_verified'])) {
            return null;
        }
        return [
            'api_key'        => (string) $s['api_key'],
            'provider'       => self::normalize_provider($s['provider'] ?? 'openai'),
            'model'          => (string) ($s['model'] ?? 'gpt-4o-mini'),
            'global_context' => (string) ($s['global_context'] ?? ''),
        ];
    }

    public static function normalize_provider($provider) {
        $provider = sanitize_key((string) $provider);
        return in_array($provider, ['openai', 'anthropic', 'google'], true) ? $provider : 'openai';
    }

    public static function maybe_seed() {
        if (!self::should_show_hub() || !current_user_can('manage_options')) {
            return;
        }
        $s = self::get_settings();
        if (!empty($s['api_key'])) {
            return;
        }
        foreach (self::active_plugins() as $meta) {
            if (empty($meta['seed_callback'])) {
                continue;
            }
            $local = call_user_func($meta['seed_callback']);
            if (!is_array($local) || empty($local['api_key'])) {
                continue;
            }
            self::update_settings([
                'api_key'          => (string) $local['api_key'],
                'api_key_verified' => !empty($local['api_key_verified']) ? 1 : 0,
                'provider'         => self::normalize_provider($local['provider'] ?? 'openai'),
                'model'            => (string) ($local['model'] ?? 'gpt-4o-mini'),
                'global_context'   => (string) ($local['global_context'] ?? ''),
            ]);
            return;
        }
    }

    public static function maybe_register_menu() {
        if (!self::should_show_hub()) {
            return;
        }
        $owner = self::elected_owner();
        // Only the elected plugin process should add the menu — all load this class,
        // but register_menu runs once per request; guard with a static flag + owner check
        // via filter so addons can claim ownership explicitly.
        $claimer = apply_filters('pewit_labs_hub_menu_owner', $owner);
        if ($claimer !== $owner) {
            // Another plugin asked to own the menu; still only register once.
        }
        static $added = false;
        if ($added) {
            return;
        }
        $added = true;

        add_menu_page(
            __('PEWIT Labs', 'pewit-labs'),
            __('PEWIT Labs', 'pewit-labs'),
            'manage_options',
            self::PAGE,
            [__CLASS__, 'render_page'],
            'dashicons-admin-generic',
            58
        );
    }

    public static function assets($hook) {
        if ($hook !== 'toplevel_page_' . self::PAGE) {
            return;
        }
        if (!self::should_show_hub()) {
            return;
        }
        wp_register_style('pewit-labs-hub', false, [], '1.0');
        wp_enqueue_style('pewit-labs-hub');
        wp_add_inline_style('pewit-labs-hub', '
            .pewit-labs-hub { max-width: 720px; }
            .pewit-labs-hub .pewit-labs-field { margin: 1em 0; }
            .pewit-labs-hub label { display: block; font-weight: 600; margin-bottom: .35em; }
            .pewit-labs-hub .description { color: #646970; }
            .pewit-labs-hub .pewit-labs-plugins { margin: 1.5em 0; padding: 0; list-style: disc inside; }
            .pewit-labs-hub .pewit-labs-actions { display: flex; gap: .5em; flex-wrap: wrap; margin-top: 1.25em; }
            .pewit-labs-hub .pewit-labs-status { margin-top: .75em; }
        ');

        wp_register_script('pewit-labs-hub', false, ['jquery'], '1.0', true);
        wp_enqueue_script('pewit-labs-hub');
        wp_localize_script('pewit-labs-hub', 'pewitLabsHub', [
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce(self::NONCE),
            'i18n'    => [
                'saved'   => __('Settings saved.', 'pewit-labs'),
                'testing' => __('Testing…', 'pewit-labs'),
                'error'   => __('Something went wrong.', 'pewit-labs'),
            ],
        ]);
        wp_add_inline_script('pewit-labs-hub', self::inline_js());
    }

    private static function inline_js() {
        return <<<'JS'
(function ($) {
  function payload() {
    return {
      nonce: pewitLabsHub.nonce,
      provider: $('#pewit_labs_provider').val(),
      model: $('#pewit_labs_model').val(),
      global_context: $('#pewit_labs_global_context').val(),
      api_key: $('#pewit_labs_api_key').val()
    };
  }
  function setStatus(text, ok) {
    var $el = $('#pewit-labs-status');
    $el.text(text).css('color', ok ? '#007017' : '#b32d2e');
  }
  $('#pewit-labs-save').on('click', function () {
    var $btn = $(this).prop('disabled', true);
    $.post(pewitLabsHub.ajaxUrl, $.extend({ action: 'pewit_labs_save_ai' }, payload()))
      .done(function (res) {
        if (res && res.success) {
          setStatus(res.data && res.data.message ? res.data.message : pewitLabsHub.i18n.saved, true);
          if (res.data && res.data.mask) {
            $('#pewit_labs_api_key_mask').text(res.data.mask);
            $('#pewit-labs-key-saved').show();
            $('#pewit_labs_api_key').val('');
          }
        } else {
          setStatus((res && res.data && res.data.message) || pewitLabsHub.i18n.error, false);
        }
      })
      .fail(function () { setStatus(pewitLabsHub.i18n.error, false); })
      .always(function () { $btn.prop('disabled', false); });
  });
  $('#pewit-labs-test').on('click', function () {
    var $btn = $(this).prop('disabled', true);
    setStatus(pewitLabsHub.i18n.testing, true);
    $.post(pewitLabsHub.ajaxUrl, $.extend({ action: 'pewit_labs_test_ai' }, payload()))
      .done(function (res) {
        if (res && res.success) {
          setStatus(res.data && res.data.message ? res.data.message : pewitLabsHub.i18n.saved, true);
          if (res.data && res.data.mask) {
            $('#pewit_labs_api_key_mask').text(res.data.mask);
            $('#pewit-labs-key-saved').show();
            $('#pewit_labs_api_key').val('');
          }
        } else {
          setStatus((res && res.data && res.data.message) || pewitLabsHub.i18n.error, false);
        }
      })
      .fail(function () { setStatus(pewitLabsHub.i18n.error, false); })
      .always(function () { $btn.prop('disabled', false); });
  });
  $('#pewit-labs-key-change').on('click', function () {
    $('#pewit-labs-key-saved').hide();
    $('#pewit_labs_api_key').focus();
  });
})(jQuery);
JS;
    }

    public static function render_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        $active = self::active_plugins();
        $s = self::get_settings();
        $provider = self::normalize_provider($s['provider'] ?? 'openai');
        $has_key = !empty($s['api_key']);
        ?>
        <div class="wrap pewit-labs-hub">
            <h1><?php echo esc_html__('PEWIT Labs', 'pewit-labs'); ?></h1>
            <p class="description">
                <?php echo esc_html__('Shared AI credentials for your PEWIT Labs plugins. Each plugin keeps its own feature settings.', 'pewit-labs'); ?>
            </p>

            <h2><?php echo esc_html__('Active plugins', 'pewit-labs'); ?></h2>
            <ul class="pewit-labs-plugins">
                <?php foreach ($active as $meta) : ?>
                    <li><?php echo esc_html($meta['label']); ?></li>
                <?php endforeach; ?>
            </ul>

            <h2><?php echo esc_html__('AI provider', 'pewit-labs'); ?></h2>
            <div class="pewit-labs-field">
                <label for="pewit_labs_provider"><?php echo esc_html__('Provider', 'pewit-labs'); ?></label>
                <select id="pewit_labs_provider">
                    <option value="openai" <?php selected($provider, 'openai'); ?>><?php echo esc_html__('OpenAI', 'pewit-labs'); ?></option>
                    <option value="anthropic" <?php selected($provider, 'anthropic'); ?>><?php echo esc_html__('Claude (Anthropic)', 'pewit-labs'); ?></option>
                    <option value="google" <?php selected($provider, 'google'); ?>><?php echo esc_html__('Gemini (Google)', 'pewit-labs'); ?></option>
                </select>
                <p class="description"><?php echo esc_html__('On WordPress 7.0+ you can also use Settings → Connectors (core AI Client). Shared keys below are the BYOK fallback.', 'pewit-labs'); ?></p>
            </div>

            <div class="pewit-labs-field">
                <label for="pewit_labs_api_key"><?php echo esc_html__('API key', 'pewit-labs'); ?></label>
                <?php if ($has_key) : ?>
                <div id="pewit-labs-key-saved">
                    <code id="pewit_labs_api_key_mask"><?php echo esc_html(self::mask_key($s['api_key'])); ?></code>
                    <button type="button" class="button button-small" id="pewit-labs-key-change"><?php echo esc_html__('Change key', 'pewit-labs'); ?></button>
                </div>
                <?php else : ?>
                <div id="pewit-labs-key-saved" style="display:none">
                    <code id="pewit_labs_api_key_mask"></code>
                    <button type="button" class="button button-small" id="pewit-labs-key-change"><?php echo esc_html__('Change key', 'pewit-labs'); ?></button>
                </div>
                <?php endif; ?>
                <input type="password" id="pewit_labs_api_key" class="regular-text" autocomplete="new-password" placeholder="sk-…" />
            </div>

            <div class="pewit-labs-field">
                <label for="pewit_labs_model"><?php echo esc_html__('Model', 'pewit-labs'); ?></label>
                <input type="text" id="pewit_labs_model" class="regular-text" value="<?php echo esc_attr($s['model']); ?>" />
            </div>

            <div class="pewit-labs-field">
                <label for="pewit_labs_global_context"><?php echo esc_html__('Global context (optional)', 'pewit-labs'); ?></label>
                <textarea id="pewit_labs_global_context" class="large-text" rows="4"><?php echo esc_textarea($s['global_context']); ?></textarea>
            </div>

            <div class="pewit-labs-actions">
                <button type="button" class="button button-primary" id="pewit-labs-save"><?php echo esc_html__('Save settings', 'pewit-labs'); ?></button>
                <button type="button" class="button" id="pewit-labs-test"><?php echo esc_html__('Save & Test API', 'pewit-labs'); ?></button>
            </div>
            <p id="pewit-labs-status" class="pewit-labs-status" aria-live="polite"></p>
        </div>
        <?php
    }

    public static function ajax_save() {
        check_ajax_referer(self::NONCE, 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'Permission denied.'], 403);
        }
        if (!self::should_show_hub()) {
            wp_send_json_error(['message' => 'Hub is not active.'], 400);
        }
        $s = self::apply_posted_settings(self::get_settings());
        self::update_settings($s);
        wp_send_json_success([
            'message' => __('Settings saved.', 'pewit-labs'),
            'mask'    => self::mask_key($s['api_key'] ?? ''),
        ]);
    }

    public static function ajax_test() {
        check_ajax_referer(self::NONCE, 'nonce');
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => 'Permission denied.'], 403);
        }
        if (!self::should_show_hub()) {
            wp_send_json_error(['message' => 'Hub is not active.'], 400);
        }
        $s = self::apply_posted_settings(self::get_settings());
        self::update_settings($s);

        $llm = self::owner_llm_class();
        if (!$llm || !method_exists($llm, 'test')) {
            wp_send_json_error(['message' => 'AI client unavailable.']);
        }
        $result = call_user_func([$llm, 'test'], [
            'api_key'     => (string) $s['api_key'],
            'provider'    => self::normalize_provider($s['provider']),
            'model'       => (string) $s['model'],
            'pro_allowed' => true,
        ]);
        $ok = !empty($result['ok']);
        if ($ok) {
            $s['api_key_verified'] = 1;
            self::update_settings($s);
            wp_send_json_success([
                'message' => (string) ($result['message'] ?? 'Connected successfully'),
                'mask'    => self::mask_key($s['api_key']),
            ]);
        }
        $s['api_key_verified'] = 0;
        self::update_settings($s);
        wp_send_json_error(['message' => (string) ($result['message'] ?? 'Connection failed')]);
    }

    private static function apply_posted_settings(array $s) {
        if (isset($_POST['provider'])) {
            $s['provider'] = self::normalize_provider(sanitize_text_field(wp_unslash($_POST['provider'])));
        }
        if (isset($_POST['model'])) {
            $s['model'] = sanitize_text_field(wp_unslash($_POST['model']));
        }
        if (isset($_POST['global_context'])) {
            $s['global_context'] = sanitize_textarea_field(wp_unslash($_POST['global_context']));
        }
        if (isset($_POST['api_key'])) {
            $incoming = sanitize_text_field(wp_unslash($_POST['api_key']));
            if ($incoming !== '') {
                if ($incoming !== ($s['api_key'] ?? '')) {
                    $s['api_key_verified'] = 0;
                }
                $s['api_key'] = $incoming;
            }
        }
        return $s;
    }

    private static function owner_llm_class() {
        $owner = self::elected_owner();
        if (!$owner || empty(self::$registry[$owner]['llm_class'])) {
            return null;
        }
        $class = self::$registry[$owner]['llm_class'];
        return class_exists($class) ? $class : null;
    }

    public static function mask_key($key) {
        $key = trim((string) $key);
        if ($key === '') {
            return '';
        }
        if (strlen($key) <= 8) {
            return str_repeat('•', 12);
        }
        return substr($key, 0, 3) . str_repeat('•', 8) . substr($key, -4);
    }

    /**
     * Notice + link for per-plugin Settings screens when hub mode is active.
     *
     * @param string $text_domain Kept for call-site compatibility; hub UI uses domain pewit-labs.
     */
    public static function render_settings_notice($text_domain = 'pewit-labs') {
        if (!self::should_show_hub()) {
            return;
        }
        unset($text_domain);
        echo '<div class="notice notice-info inline" style="margin:0 0 1em;padding:8px 12px;">';
        echo '<p style="margin:0;">';
        echo esc_html__('Several PEWIT Labs plugins are active. Shared AI credentials (provider, API key, model) are managed here:', 'pewit-labs');
        echo ' <a href="' . esc_url(self::admin_url()) . '"><strong>' . esc_html__('PEWIT Labs → AI settings', 'pewit-labs') . '</strong></a>';
        echo '</p></div>';
    }
}
