<?php
/**
 * WS7: WordPress Multisite batch-attach.
 *
 * On a network, connecting every subsite individually is friction and risks
 * fragmenting them across organizations. This adds a Network Admin page that
 * propagates the primary site's Encypher connection (API key + organization)
 * to every site in the network via get_sites() + switch_to_blog(), so the whole
 * network reports to ONE organization.
 *
 * The primary site is connected first through the normal Encypher > Settings
 * flow (one-click Activate or OAuth, which resolves the network admin's
 * organization); this page then fans that connection out to the rest.
 *
 * @package EncypherProvenance
 */

namespace EncypherProvenance;

if (! defined('ABSPATH')) {
    exit;
}
require_once __DIR__ . '/class-encypher-capabilities.php';

class Multisite
{
    private const ATTACH_ACTION = 'encypher_attach_network';
    private const SETTINGS_KEY = 'encypher_provenance_settings';

    /**
     * Register network-admin hooks. No-op on single-site installs.
     */
    public function register_hooks(): void
    {
        if (! is_multisite() || ! Capabilities::allows(Capabilities::MULTISITE)) {
            return;
        }

        add_action('network_admin_menu', [$this, 'register_network_page']);
        add_action('admin_post_' . self::ATTACH_ACTION, [$this, 'handle_attach']);
    }

    /**
     * Add the network-settings subpage.
     */
    public function register_network_page(): void
    {
        if (! Capabilities::allows(Capabilities::MULTISITE)) {
            return;
        }
        add_submenu_page(
            'settings.php',
            __('Encypher Network Provenance', 'encypher-provenance'),
            __('Encypher Provenance', 'encypher-provenance'),
            'manage_network_options',
            'encypher-network',
            [$this, 'render_network_page']
        );
    }

    /**
     * Read the Encypher connection and server entitlement snapshot from the
     * current (switched) site.
     *
     * @return array<string,mixed>
     */
    private function connection_for_current_site(): array
    {
        $s = get_option(self::SETTINGS_KEY, []);
        if (! is_array($s)) {
            $s = [];
        }

        return [
            'api_key'           => (string) ($s['api_key'] ?? ''),
            'api_base_url'      => (string) ($s['api_base_url'] ?? 'https://api.encypher.com/api/v1'),
            'organization_id'   => (string) ($s['organization_id'] ?? ''),
            'organization_name' => (string) ($s['organization_name'] ?? ''),
            'tier'              => (string) ($s['tier'] ?? 'free'),
            'entitlements'      => Capabilities::snapshot(),
        ];
    }

    /**
     * Render the network batch-attach page.
     */
    public function render_network_page(): void
    {
        if (! current_user_can('manage_network_options')) {
            wp_die(esc_html__('You do not have permission to manage this network.', 'encypher-provenance'));
        }
        if (! Capabilities::allows(Capabilities::MULTISITE)) {
            wp_die(esc_html__('Encypher has not enabled network attachment for this account.', 'encypher-provenance'));
        }

        $main_site_id = (int) get_main_site_id();
        switch_to_blog($main_site_id);
        $source = $this->connection_for_current_site();
        restore_current_blog();

        echo '<div class="wrap">';
        echo '<h1>' . esc_html__('Encypher Network Provenance', 'encypher-provenance') . '</h1>';

        $attached = isset($_GET['encypher_attached']) ? (int) $_GET['encypher_attached'] : -1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        if ($attached >= 0) {
            echo '<div class="notice notice-success is-dismissible"><p>' . sprintf(
                esc_html(
                    /* translators: %d: number of network sites attached. */
                    _n('Attached %d site to the organization.', 'Attached %d sites to the organization.', $attached, 'encypher-provenance')
                ),
                (int) $attached
            ) . '</p></div>';
        }

        if ('' === $source['api_key']) {
            echo '<div class="notice notice-warning"><p>' . esc_html__('Connect the primary network site to Encypher first (Encypher > Settings on the main site), then return here to attach the rest of the network to the same organization.', 'encypher-provenance') . '</p></div>';
        } else {
            echo '<p>' . sprintf(
                /* translators: %s: organization name. */
                esc_html__('The primary site is connected to organization %s. Attaching links every network site to this same organization.', 'encypher-provenance'),
                '<strong>' . esc_html($source['organization_name'] !== '' ? $source['organization_name'] : ($source['organization_id'] !== '' ? $source['organization_id'] : __('(unnamed)', 'encypher-provenance'))) . '</strong>'
            ) . '</p>';
        }

        echo '<table class="widefat striped"><thead><tr>';
        echo '<th>' . esc_html__('Site', 'encypher-provenance') . '</th>';
        echo '<th>' . esc_html__('Organization', 'encypher-provenance') . '</th>';
        echo '<th>' . esc_html__('Status', 'encypher-provenance') . '</th>';
        echo '</tr></thead><tbody>';

        foreach (get_sites(['number' => 0]) as $site) {
            $blog_id = (int) $site->blog_id;
            switch_to_blog($blog_id);
            $conn = $this->connection_for_current_site();
            $name = get_bloginfo('name');
            $url  = home_url();
            restore_current_blog();

            $connected = '' !== $conn['api_key'];
            $same_org  = $connected && '' !== $source['organization_id'] && $conn['organization_id'] === $source['organization_id'];
            if (! $connected) {
                $status = __('Not connected', 'encypher-provenance');
            } elseif ($same_org) {
                $status = __('Connected (this organization)', 'encypher-provenance');
            } else {
                $status = __('Connected (different organization)', 'encypher-provenance');
            }

            echo '<tr>';
            echo '<td>' . esc_html($name) . '<br><small>' . esc_html($url) . ($blog_id === $main_site_id ? ' — ' . esc_html__('primary', 'encypher-provenance') : '') . '</small></td>';
            echo '<td>' . esc_html($conn['organization_name'] !== '' ? $conn['organization_name'] : ($conn['organization_id'] !== '' ? $conn['organization_id'] : '—')) . '</td>';
            echo '<td>' . esc_html($status) . '</td>';
            echo '</tr>';
        }

        echo '</tbody></table>';

        if ('' !== $source['api_key']) {
            echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin-top:1em">';
            echo '<input type="hidden" name="action" value="' . esc_attr(self::ATTACH_ACTION) . '">';
            wp_nonce_field(self::ATTACH_ACTION);
            submit_button(__('Attach all network sites to this organization', 'encypher-provenance'));
            echo '</form>';
        }

        echo '</div>';
    }

    /**
     * Handle the batch-attach form submission.
     */
    public function handle_attach(): void
    {
        if (! current_user_can('manage_network_options')) {
            wp_die(esc_html__('You do not have permission to manage this network.', 'encypher-provenance'));
        }
        if (! Capabilities::allows(Capabilities::MULTISITE)) {
            wp_die(esc_html__('Encypher has not enabled network attachment for this account.', 'encypher-provenance'));
        }
        check_admin_referer(self::ATTACH_ACTION);

        $main_site_id = (int) get_main_site_id();
        switch_to_blog($main_site_id);
        $source = $this->connection_for_current_site();
        restore_current_blog();

        $count = $this->attach_all_sites($source);

        wp_safe_redirect(
            add_query_arg(
                ['page' => 'encypher-network', 'encypher_attached' => $count],
                network_admin_url('settings.php')
            )
        );
        exit;
    }

    /**
     * Propagate the source connection to every site in the network.
     *
     * Only the connection fields are overwritten; per-site preferences (badge,
     * auto-sign, segmentation, etc.) are preserved. Idempotent.
     *
     * @param array<string,mixed> $source Connection and entitlement snapshot from the primary site.
     * @return int Number of sites attached.
     */
    public function attach_all_sites(array $source): int
    {
        if ('' === (string) ($source['api_key'] ?? '')) {
            return 0;
        }
        $entitlements = isset($source['entitlements']) && is_array($source['entitlements'])
            ? $source['entitlements']
            : [];
        if (! Capabilities::snapshot_allows($entitlements, Capabilities::MULTISITE)) {
            return 0;
        }

        $attached = 0;
        foreach (get_sites(['number' => 0, 'fields' => 'ids']) as $blog_id) {
            $blog_id = (int) $blog_id;
            switch_to_blog($blog_id);

            $settings = get_option(self::SETTINGS_KEY, []);
            if (! is_array($settings)) {
                $settings = [];
            }
            $settings['api_key']           = (string) $source['api_key'];
            $settings['api_base_url']      = (string) ($source['api_base_url'] ?? 'https://api.encypher.com/api/v1');
            $settings['organization_id']   = (string) ($source['organization_id'] ?? '');
            $settings['organization_name'] = (string) ($source['organization_name'] ?? '');
            $settings['tier']                = (string) ($source['tier'] ?? 'free');
            update_option(self::SETTINGS_KEY, $settings);
            update_option(Capabilities::OPTION_KEY, $entitlements, false);

            restore_current_blog();
            $attached++;
        }

        return $attached;
    }
}
