<?php
/**
 * Installation identity, clone detection, and non-production signing safety.
 *
 * @package EncypherProvenance
 */

namespace EncypherProvenance;

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

final class EnvironmentGuard
{
    public const IDENTITY_OPTION = 'encypher_provenance_installation_identity';

    public function register_hooks(): void
    {
        add_action('init', [self::class, 'ensure_identity'], 5);
        add_action('admin_notices', [$this, 'render_notice']);
        add_action('admin_post_encypher_mark_staging_clone', [$this, 'mark_staging_clone']);
        add_action('admin_post_encypher_rebind_installation', [$this, 'rebind_installation']);
    }

    /**
     * @return array<string,mixed>
     */
    public static function ensure_identity(): array
    {
        $stored = get_option(self::IDENTITY_OPTION, []);
        if (! is_array($stored) || empty($stored['installation_id'])) {
            $stored = self::current_identity();
            $stored['installation_id'] = function_exists('wp_generate_uuid4')
                ? wp_generate_uuid4()
                : hash('sha256', uniqid('encypher-', true));
            $stored['mode'] = 'primary';
            $stored['bound_at'] = gmdate('c');
            update_option(self::IDENTITY_OPTION, $stored, false);
        }
        return $stored;
    }

    /**
     * @return array<string,mixed>
     */
    private static function current_identity(): array
    {
        // Read every fact defensively: activation and CLI contexts can reach
        // this before the multisite helpers are available, and a fatal here
        // would take signing down instead of closing it.
        $multisite = function_exists('is_multisite') && is_multisite();
        $home_url = function_exists('home_url') ? (string) home_url('/') : '';

        return [
            'home_url' => rtrim($home_url, '/'),
            'environment' => function_exists('wp_get_environment_type')
                ? (string) wp_get_environment_type()
                : 'production',
            'multisite' => $multisite,
            'network_id' => $multisite && function_exists('get_current_network_id')
                ? (int) get_current_network_id()
                : 0,
            'blog_id' => $multisite && function_exists('get_current_blog_id')
                ? (int) get_current_blog_id()
                : 0,
        ];
    }

    /**
     * @return array<string,mixed>
     */
    public static function status(): array
    {
        $stored = self::ensure_identity();
        $current = self::current_identity();
        $mismatch = false;
        foreach (['home_url', 'multisite', 'network_id', 'blog_id'] as $field) {
            if (($stored[$field] ?? null) !== ($current[$field] ?? null)) {
                $mismatch = true;
                break;
            }
        }

        $environment = (string) $current['environment'];
        $non_production = in_array($environment, ['local', 'development', 'staging'], true);
        $mode = (string) ($stored['mode'] ?? 'primary');

        return [
            'installation_id' => (string) ($stored['installation_id'] ?? ''),
            'bound_home_url' => (string) ($stored['home_url'] ?? ''),
            'current_home_url' => (string) $current['home_url'],
            'environment' => $environment,
            'mode' => $mode,
            'clone_suspected' => $mismatch,
            'non_production' => $non_production,
            'network_id' => (int) $current['network_id'],
            'blog_id' => (int) $current['blog_id'],
        ];
    }

    /**
     * Signing is closed on suspected clones and deliberate staging clones.
     * Local/development/staging installs require one explicit local opt-in.
     *
     * @param array<string,mixed>|null $settings
     */
    public static function signing_allowed(?array $settings = null): bool
    {
        $status = self::status();
        if (! empty($status['clone_suspected']) || 'staging_clone' === $status['mode']) {
            return false;
        }
        if (empty($status['non_production'])) {
            return true;
        }
        if (null === $settings) {
            $settings = get_option('encypher_provenance_settings', []);
        }
        return is_array($settings) && ! empty($settings['allow_non_production_signing']);
    }

    public function mark_staging_clone(): void
    {
        $this->authorize_action('encypher_mark_staging_clone');
        $previous = self::ensure_identity();
        $identity = self::current_identity();
        $identity['installation_id'] = function_exists('wp_generate_uuid4')
            ? wp_generate_uuid4()
            : hash('sha256', uniqid('encypher-', true));
        $identity['parent_installation_id'] = (string) ($previous['installation_id'] ?? '');
        $identity['mode'] = 'staging_clone';
        $identity['bound_at'] = gmdate('c');
        update_option(self::IDENTITY_OPTION, $identity, false);
        $this->redirect_with_state('staging-clone');
    }

    public function rebind_installation(): void
    {
        $this->authorize_action('encypher_rebind_installation');
        $previous = self::ensure_identity();
        $identity = self::current_identity();
        $identity['installation_id'] = (string) ($previous['installation_id'] ?? '');
        $identity['mode'] = 'primary';
        $identity['bound_at'] = gmdate('c');
        update_option(self::IDENTITY_OPTION, $identity, false);
        $this->redirect_with_state('rebound');
    }

    private function authorize_action(string $action): void
    {
        if (! current_user_can('manage_options')) {
            wp_die(esc_html__('You are not allowed to change the Encypher installation identity.', 'encypher-provenance'), '', ['response' => 403]);
        }
        check_admin_referer($action);
    }

    private function redirect_with_state(string $state): void
    {
        wp_safe_redirect(add_query_arg([
            'page' => 'encypher',
            'encypher_environment' => $state,
        ], admin_url('admin.php')));
        exit;
    }

    public function render_notice(): void
    {
        if (! current_user_can('manage_options')) {
            return;
        }
        $status = self::status();
        if (empty($status['clone_suspected']) && 'staging_clone' !== $status['mode']) {
            return;
        }

        if ('staging_clone' === $status['mode']) {
            echo '<div class="notice notice-info"><p>';
            echo esc_html__('Encypher signing is disabled because this installation is marked as a staging clone. Existing provenance remains visible and read-only.', 'encypher-provenance');
            echo '</p></div>';
            return;
        }

        $staging_url = wp_nonce_url(admin_url('admin-post.php?action=encypher_mark_staging_clone'), 'encypher_mark_staging_clone');
        $rebind_url = wp_nonce_url(admin_url('admin-post.php?action=encypher_rebind_installation'), 'encypher_rebind_installation');
        echo '<div class="notice notice-warning"><p><strong>';
        echo esc_html__('Encypher detected a site clone or domain change. Signing is paused.', 'encypher-provenance');
        echo '</strong></p><p>';
        echo '<a class="button" href="' . esc_url($staging_url) . '">' . esc_html__('This is a staging clone', 'encypher-provenance') . '</a> ';
        echo '<a class="button button-primary" href="' . esc_url($rebind_url) . '">' . esc_html__('This site moved', 'encypher-provenance') . '</a>';
        echo '</p></div>';
    }
}
