<?php
/**
 * 247ChatMate — Agency client remote setup key foundation
 *
 * Checkpoint: AGENCYKEYAGENCYMOVECOLLAPSE1
 *
 * Purpose:
 * - Let a client/end-user WordPress site generate a one-time setup key.
 * - Store only the persistent hash locally.
 * - Show the plain key once to the site admin so an agency can later connect/push setup securely.
 * - Support the remote setup push endpoint, local test facility and key lifecycle display.
 *
 * Does not:
 * - Store plain setup keys permanently.
 * - Store WordPress admin usernames/passwords.
 * - Activate paid licences or touch agency seat counts.
 */

defined('ABSPATH') || exit;

if (!defined('MATEWA_AGENCY_CLIENT_SETUP_KEY_OPTION')) {
    define('MATEWA_AGENCY_CLIENT_SETUP_KEY_OPTION', 'matewa_agency_client_setup_key');
}

if (!defined('MATEWA_AGENCY_CLIENT_SETUP_KEY_TTL')) {
    define('MATEWA_AGENCY_CLIENT_SETUP_KEY_TTL', DAY_IN_SECONDS);
}

if (!function_exists('matewa_agency_client_setup_key_flash_transient_name')) {
    function matewa_agency_client_setup_key_flash_transient_name() {
        $user_id = function_exists('get_current_user_id') ? absint(get_current_user_id()) : 0;
        return 'matewa_agency_setup_key_flash_' . $user_id;
    }
}

if (!function_exists('matewa_agency_client_setup_key_redirect_url')) {
    function matewa_agency_client_setup_key_redirect_url($notice = '', $return_section = 'agency') {
        $return_section = in_array((string) $return_section, array('agency', 'setup'), true) ? (string) $return_section : 'agency';
        $args = array(
            'page'                 => '247chatmate',
            'matewa_saved_section' => $return_section,
            'matewa_scroll_target' => 'setup_key',
        );
        if ('' !== (string) $notice) {
            $args['matewa_setup_key_notice'] = sanitize_key((string) $notice);
        }

        $anchor = 'agency' === $return_section ? '#matewa-agency-client-setup-key-agency-panel' : '#matewa-setup-agency-key';
        return add_query_arg($args, admin_url('admin.php')) . $anchor;
    }
}

if (!function_exists('matewa_agency_client_setup_key_redirect')) {
    function matewa_agency_client_setup_key_redirect($notice, $return_section = 'agency') {
        wp_safe_redirect(matewa_agency_client_setup_key_redirect_url($notice, $return_section));
        exit;
    }
}

if (!function_exists('matewa_agency_client_setup_key_hash')) {
    function matewa_agency_client_setup_key_hash($plain_key) {
        $plain_key = (string) $plain_key;
        if (function_exists('wp_hash_password')) {
            return wp_hash_password($plain_key);
        }
        return function_exists('password_hash') ? password_hash($plain_key, PASSWORD_DEFAULT) : hash('sha256', $plain_key);
    }
}

if (!function_exists('matewa_agency_client_setup_key_check_hash')) {
    function matewa_agency_client_setup_key_check_hash($plain_key, $hash) {
        $plain_key = (string) $plain_key;
        $hash = (string) $hash;
        if ('' === $plain_key || '' === $hash) {
            return false;
        }
        if (function_exists('wp_check_password')) {
            return (bool) wp_check_password($plain_key, $hash);
        }
        if (function_exists('password_verify')) {
            return (bool) password_verify($plain_key, $hash);
        }
        return hash_equals($hash, hash('sha256', $plain_key));
    }
}

if (!function_exists('matewa_agency_client_setup_key_generate_plain')) {
    function matewa_agency_client_setup_key_generate_plain() {
        if (function_exists('wp_generate_password')) {
            return 'cmsetup_' . wp_generate_password(40, false, false);
        }

        try {
            return 'cmsetup_' . bin2hex(random_bytes(20));
        } catch (Exception $exception) {
            return 'cmsetup_' . wp_rand(1000000000, 9999999999) . time();
        }
    }
}

if (!function_exists('matewa_agency_client_setup_key_get_record')) {
    function matewa_agency_client_setup_key_get_record() {
        $record = get_option(MATEWA_AGENCY_CLIENT_SETUP_KEY_OPTION, array());
        return is_array($record) ? $record : array();
    }
}

if (!function_exists('matewa_agency_client_setup_key_is_active')) {
    function matewa_agency_client_setup_key_is_active($record = null) {
        $record = is_array($record) ? $record : matewa_agency_client_setup_key_get_record();
        if (empty($record['hash']) || empty($record['key_id'])) {
            return false;
        }
        if (!empty($record['revoked_at']) || !empty($record['used_at'])) {
            return false;
        }
        $expires_at = isset($record['expires_at']) ? absint($record['expires_at']) : 0;
        return $expires_at > time();
    }
}

if (!function_exists('matewa_agency_client_setup_key_status_label')) {
    function matewa_agency_client_setup_key_status_label($record = null) {
        $record = is_array($record) ? $record : matewa_agency_client_setup_key_get_record();
        if (empty($record['hash']) || empty($record['key_id'])) {
            return 'No setup key generated';
        }
        if (!empty($record['used_at'])) {
            return 'Used';
        }
        if (!empty($record['revoked_at'])) {
            return 'Revoked';
        }
        $expires_at = isset($record['expires_at']) ? absint($record['expires_at']) : 0;
        if ($expires_at <= time()) {
            return 'Expired';
        }
        return 'Active';
    }
}

if (!function_exists('matewa_agency_client_setup_key_create')) {
    function matewa_agency_client_setup_key_create() {
        $plain_key = matewa_agency_client_setup_key_generate_plain();
        $created_at = time();
        $expires_at = $created_at + absint(MATEWA_AGENCY_CLIENT_SETUP_KEY_TTL);
        $key_id = 'setup_' . substr(hash('sha256', $plain_key . '|' . $created_at . '|' . wp_salt('auth')), 0, 16);
        $site_url = home_url('/');
        $home_host = wp_parse_url($site_url, PHP_URL_HOST);

        $record = array(
            'checkpoint'              => 'AGENCYKEYAGENCYMOVECOLLAPSE1',
            'key_id'                  => sanitize_key($key_id),
            'hash'                    => matewa_agency_client_setup_key_hash($plain_key),
            'created_at'              => $created_at,
            'expires_at'              => $expires_at,
            'used_at'                 => 0,
            'revoked_at'              => 0,
            'site_url'                => esc_url_raw($site_url),
            'site_host'               => sanitize_text_field(is_string($home_host) ? strtolower($home_host) : ''),
            'generated_by_user_id'    => function_exists('get_current_user_id') ? absint(get_current_user_id()) : 0,
            'source_of_truth'         => 'client_site_plugin_options',
            'plain_key_stored'        => false,
            'remote_push_enabled'     => true,
            'remote_push_checkpoint'  => 'AGENCYKEYAGENCYMOVECOLLAPSE1',
        );

        update_option(MATEWA_AGENCY_CLIENT_SETUP_KEY_OPTION, $record, false);
        set_transient(
            matewa_agency_client_setup_key_flash_transient_name(),
            array(
                'key_id'     => $record['key_id'],
                'plain_key'  => $plain_key,
                'created_at' => $created_at,
            ),
            10 * MINUTE_IN_SECONDS
        );

        return array('plain_key' => $plain_key, 'record' => $record);
    }
}

if (!function_exists('matewa_agency_client_setup_key_revoke')) {
    function matewa_agency_client_setup_key_revoke() {
        $record = matewa_agency_client_setup_key_get_record();
        if (!empty($record)) {
            $record['revoked_at'] = time();
            update_option(MATEWA_AGENCY_CLIENT_SETUP_KEY_OPTION, $record, false);
        }
        delete_transient(matewa_agency_client_setup_key_flash_transient_name());
        return $record;
    }
}

if (!function_exists('matewa_agency_client_setup_key_verify')) {
    function matewa_agency_client_setup_key_verify($plain_key) {
        $record = matewa_agency_client_setup_key_get_record();
        if (!matewa_agency_client_setup_key_is_active($record)) {
            return array('ok' => false, 'reason' => 'inactive_or_expired', 'record' => $record);
        }
        $ok = matewa_agency_client_setup_key_check_hash($plain_key, $record['hash'] ?? '');
        return array('ok' => $ok, 'reason' => $ok ? 'verified' : 'invalid_key', 'record' => $record);
    }
}

if (!function_exists('matewa_agency_client_setup_key_mark_used')) {
    function matewa_agency_client_setup_key_mark_used($key_id = '') {
        $record = matewa_agency_client_setup_key_get_record();
        $key_id = sanitize_key((string) $key_id);
        if (empty($record['key_id']) || ('' !== $key_id && $key_id !== $record['key_id'])) {
            return false;
        }
        $record['used_at'] = time();
        update_option(MATEWA_AGENCY_CLIENT_SETUP_KEY_OPTION, $record, false);
        delete_transient(matewa_agency_client_setup_key_flash_transient_name());
        $generated_by_user_id = isset($record['generated_by_user_id']) ? absint($record['generated_by_user_id']) : 0;
        if ($generated_by_user_id > 0) {
            delete_transient('matewa_agency_setup_key_flash_' . $generated_by_user_id);
        }
        return true;
    }
}

if (!function_exists('matewa_agency_client_setup_key_handle_generate')) {
    function matewa_agency_client_setup_key_handle_generate() {
        if (!is_admin() || !current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to generate setup keys.', '247chatmate'));
        }

        check_admin_referer('matewa_agency_client_setup_key_generate', 'matewa_agency_client_setup_key_nonce');
        matewa_agency_client_setup_key_create();
        $return_section = isset($_POST['matewa_setup_key_return_section']) ? sanitize_key(wp_unslash($_POST['matewa_setup_key_return_section'])) : 'agency';
        matewa_agency_client_setup_key_redirect('generated', $return_section);
    }
}
add_action('admin_post_matewa_agency_client_setup_key_generate', 'matewa_agency_client_setup_key_handle_generate');

if (!function_exists('matewa_agency_client_setup_key_handle_revoke')) {
    function matewa_agency_client_setup_key_handle_revoke() {
        if (!is_admin() || !current_user_can('manage_options')) {
            wp_die(esc_html__('You do not have permission to revoke setup keys.', '247chatmate'));
        }

        check_admin_referer('matewa_agency_client_setup_key_revoke', 'matewa_agency_client_setup_key_revoke_nonce');
        matewa_agency_client_setup_key_revoke();
        $return_section = isset($_POST['matewa_setup_key_return_section']) ? sanitize_key(wp_unslash($_POST['matewa_setup_key_return_section'])) : 'agency';
        matewa_agency_client_setup_key_redirect('revoked', $return_section);
    }
}
add_action('admin_post_matewa_agency_client_setup_key_revoke', 'matewa_agency_client_setup_key_handle_revoke');

if (!function_exists('matewa_agency_client_setup_key_notice_message')) {
    function matewa_agency_client_setup_key_notice_message($notice) {
        $notice = sanitize_key((string) $notice);
        $messages = array(
            'generated' => array('type' => 'success', 'message' => 'One-time setup key generated. Copy it now — the plain key is only shown briefly.'),
            'revoked'   => array('type' => 'warning', 'message' => 'Setup key revoked. Remote setup cannot use that key.'),
        );
        return isset($messages[$notice]) ? $messages[$notice] : array('type' => '', 'message' => '');
    }
}

if (!function_exists('matewa_agency_client_setup_key_render_panel')) {
    function matewa_agency_client_setup_key_render_panel($return_section = 'agency') {
        $return_section = in_array((string) $return_section, array('agency', 'setup'), true) ? (string) $return_section : 'agency';
        $notice = isset($_GET['matewa_setup_key_notice']) ? sanitize_key(wp_unslash($_GET['matewa_setup_key_notice'])) : '';
        $notice_data = matewa_agency_client_setup_key_notice_message($notice);
        $record = matewa_agency_client_setup_key_get_record();
        $is_active = matewa_agency_client_setup_key_is_active($record);
        $status_label = matewa_agency_client_setup_key_status_label($record);
        $expires_at = isset($record['expires_at']) ? absint($record['expires_at']) : 0;
        $created_at = isset($record['created_at']) ? absint($record['created_at']) : 0;
        $key_id = sanitize_key((string) ($record['key_id'] ?? ''));
        $used_at = isset($record['used_at']) ? absint($record['used_at']) : 0;
        $revoked_at = isset($record['revoked_at']) ? absint($record['revoked_at']) : 0;
        $last_remote_push_at = isset($record['last_remote_push_at']) ? absint($record['last_remote_push_at']) : 0;
        $last_remote_setup_pack_id = isset($record['last_remote_setup_pack_id']) ? sanitize_key((string) $record['last_remote_setup_pack_id']) : '';
        $last_remote_push_hash = isset($record['last_remote_push_payload_hash'])
            ? sanitize_text_field((string) $record['last_remote_push_payload_hash'])
            : (isset($record['last_remote_payload_hash']) ? sanitize_text_field((string) $record['last_remote_payload_hash']) : '');
        $flash = get_transient(matewa_agency_client_setup_key_flash_transient_name());
        $flash = is_array($flash) ? $flash : array();
        $plain_key = '';
        if ($is_active && !empty($flash['key_id']) && $key_id === sanitize_key((string) $flash['key_id']) && !empty($flash['plain_key'])) {
            $plain_key = (string) $flash['plain_key'];
        }
        $panel_id = 'agency' === $return_section ? 'matewa-agency-client-setup-key-agency-panel' : 'matewa-agency-client-setup-key-panel';
        ?>
        <section id="<?php echo esc_attr($panel_id); ?>" class="matewa-agency-client-import-panel matewa-agency-client-setup-key-panel" aria-label="Agency remote setup key">
            <div class="matewa-agency-client-import-head">
                <div>
                    <span class="matewa-section-kicker">Remote setup foundation</span>
                    <h3>One-time agency setup key</h3>
                    <p>Generate a temporary key so an agency can later connect this installed client plugin without needing WordPress admin passwords.</p>
                </div>
                <em><?php echo esc_html($status_label); ?></em>
            </div>

            <?php if (!empty($notice_data['message'])) : ?>
                <div class="matewa-agency-client-import-notice is-<?php echo esc_attr($notice_data['type']); ?>" role="status" aria-live="polite">
                    <?php echo esc_html($notice_data['message']); ?>
                </div>
            <?php endif; ?>

            <div class="matewa-agency-client-setup-key-grid" aria-label="Current setup key details">
                <div>
                    <span>Status</span>
                    <strong><?php echo esc_html($status_label); ?></strong>
                </div>
                <div>
                    <span>Key ID</span>
                    <strong><?php echo esc_html('' !== $key_id ? $key_id : 'Not generated'); ?></strong>
                </div>
                <div>
                    <span>Created</span>
                    <strong><?php echo esc_html($created_at > 0 ? date_i18n(get_option('date_format', 'j M Y') . ' ' . get_option('time_format', 'H:i'), $created_at) : 'Not generated'); ?></strong>
                </div>
                <div>
                    <span>Expires</span>
                    <strong><?php echo esc_html($expires_at > 0 ? date_i18n(get_option('date_format', 'j M Y') . ' ' . get_option('time_format', 'H:i'), $expires_at) : 'Not generated'); ?></strong>
                </div>
                <div>
                    <span>Used</span>
                    <strong><?php echo esc_html($used_at > 0 ? date_i18n(get_option('date_format', 'j M Y') . ' ' . get_option('time_format', 'H:i'), $used_at) : 'Not used'); ?></strong>
                </div>
                <div>
                    <span>Revoked</span>
                    <strong><?php echo esc_html($revoked_at > 0 ? date_i18n(get_option('date_format', 'j M Y') . ' ' . get_option('time_format', 'H:i'), $revoked_at) : 'Not revoked'); ?></strong>
                </div>
                <div>
                    <span>Last remote import</span>
                    <strong><?php echo esc_html($last_remote_push_at > 0 ? date_i18n(get_option('date_format', 'j M Y') . ' ' . get_option('time_format', 'H:i'), $last_remote_push_at) : 'None yet'); ?></strong>
                </div>
                <div>
                    <span>Last setup pack</span>
                    <strong><?php echo esc_html('' !== $last_remote_setup_pack_id ? $last_remote_setup_pack_id : 'None yet'); ?></strong>
                </div>
            </div>

            <?php if ('' !== $last_remote_push_hash) : ?>
                <div class="matewa-agency-client-import-last" aria-label="Last remote setup hash">
                    <strong>Last remote payload hash</strong>
                    <span><?php echo esc_html(substr($last_remote_push_hash, 0, 18) . '…'); ?></span>
                    <small>Plain setup keys are still not stored. This hash identifies the imported payload only.</small>
                </div>
            <?php endif; ?>

            <?php if ('' !== $plain_key) : ?>
                <div class="matewa-agency-client-setup-key-output" aria-label="Generated one-time setup key">
                    <label for="matewa_agency_client_setup_key_plain">Copy this key now</label>
                    <input type="text" id="matewa_agency_client_setup_key_plain" class="regular-text" readonly value="<?php echo esc_attr($plain_key); ?>" onclick="this.select();">
                    <small>The plain key is not stored permanently. The client site keeps only the hashed key record.</small>
                </div>
            <?php elseif ($is_active) : ?>
                <div class="matewa-agency-client-import-last">
                    <strong>Active key hidden</strong>
                    <span>The setup key is active, but the plain key is only shown immediately after generation.</span>
                    <small>Generate a new key if the agency needs another copy.</small>
                </div>
            <?php elseif ($used_at > 0) : ?>
                <div class="matewa-agency-client-import-last">
                    <strong>Setup key consumed</strong>
                    <span>This one-time key has already been used for a remote setup import.</span>
                    <small>Generate a fresh setup key before the agency pushes another update.</small>
                </div>
            <?php endif; ?>

            <div class="matewa-agency-client-import-actions">
                <button type="submit" class="button button-primary" form="matewa-agency-client-setup-key-generate-form" name="matewa_setup_key_return_section" value="<?php echo esc_attr($return_section); ?>"><?php echo esc_html($is_active ? 'Generate new setup key' : 'Generate setup key'); ?></button>
                <?php if (!empty($record['key_id']) && empty($record['used_at']) && empty($record['revoked_at'])) : ?>
                    <button type="submit" class="button button-secondary matewa-button-muted" form="matewa-agency-client-setup-key-revoke-form" name="matewa_setup_key_return_section" value="<?php echo esc_attr($return_section); ?>">Revoke current key</button>
                <?php endif; ?>
            </div>

            <p class="description">The agency can use an active one-time key to push a saved setup pack. After a successful import, the key is consumed and the client site remains the source of truth.</p>
        </section>
        <?php
    }
}

if (!function_exists('matewa_agency_client_setup_key_render_action_forms')) {
    function matewa_agency_client_setup_key_render_action_forms() {
        ?>
        <form id="matewa-agency-client-setup-key-generate-form" class="matewa-admin-hidden-action-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" aria-hidden="true">
            <input type="hidden" name="action" value="matewa_agency_client_setup_key_generate">
            <?php wp_nonce_field('matewa_agency_client_setup_key_generate', 'matewa_agency_client_setup_key_nonce'); ?>
        </form>
        <form id="matewa-agency-client-setup-key-revoke-form" class="matewa-admin-hidden-action-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" aria-hidden="true">
            <input type="hidden" name="action" value="matewa_agency_client_setup_key_revoke">
            <?php wp_nonce_field('matewa_agency_client_setup_key_revoke', 'matewa_agency_client_setup_key_revoke_nonce'); ?>
        </form>
        <?php
    }
}
