<?php

namespace Fotogenic_AI;

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

final class Plugin {
    private const BULK_HOUSEKEEPING_INITIAL_DELAY = 60;
	private const STORE_QUEUE_PURGE_HOOK = 'fotogenic_ai_store_queue_purge';

    private static ?Plugin $instance = null;

    /** @var Compat_Manager|null */
    private ?Compat_Manager $compat_manager = null;

    private function __construct() {}

    public static function instance(): Plugin {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public function init(): void {
        $this->register_autoload();
        $this->register_activation_checks();
		$this->register_platform_diagnostics();
		if ( ! $this->capabilities()->activation_status( false )['available'] ) {
			return;
		}
        Universal_Data_Migration::instance()->register();
        Auth_Session::instance()->init();
		Workflow_Credit_Settlement::register();

        add_action( 'plugins_loaded', [ $this, 'register_woocommerce_cache_invalidation' ], 20 );

        add_action( 'init', [ $this, 'register_background_finalizer' ], 5 );
        add_action( 'init', [ $this, 'register_bulk_runner' ], 5 );
		add_action( 'init', [ $this, 'register_store_queue_runner' ], 5 );
        add_action( 'admin_init', [ $this, 'register_privacy_policy_content' ] );
        add_action( 'fotogenic_ai_log_purge', [ Logger::instance(), 'run_purge' ] );
		add_action( self::STORE_QUEUE_PURGE_HOOK, [ Store_Queue_Repo::instance(), 'purge_expired' ] );
        $this->schedule_log_purge();
		$this->schedule_store_queue_purge();

        if ( is_admin() ) {
            $this->init_admin();
        }
        $this->init_rest();
    }

    public function compat(): Compat_Manager {
        if ( null === $this->compat_manager ) {
            $this->compat_manager = new Compat_Manager();
        }
        return $this->compat_manager;
    }

	public function capabilities(): Platform_Capabilities {
		return Platform_Capabilities::instance();
	}

    /**
     * Register WooCommerce-dependent cache invalidation after all active plugins load.
     */
    public function register_woocommerce_cache_invalidation(): void {
        if ( ! fotogenic_ai_woocommerce_available() ) {
            return;
        }

        fotogenic_ai_load_rest_bucket();
        $this->compat()->register_cache_invalidation();
    }

    /**
     * Register background finalization hook on every request (cron, AS, REST, etc.).
     * Do not rely on REST requests for the worker callback to be registered.
     */
    public function register_background_finalizer(): void {
		if ( ! Background_Runtime_State::is_enabled() || ! Universal_Data_Migration::instance()->is_ready() ) {
            return;
        }
        Background_Finalizer::instance()->register();
    }

    /**
     * Register bulk runner hook on every request (cron, AS, REST, etc.).
     */
    public function register_bulk_runner(): void {
		if ( ! Background_Runtime_State::is_enabled() || ! Universal_Data_Migration::instance()->is_ready() ) {
            return;
        }
        Bulk_Run_Runner::instance()->register();
    }

	public function register_store_queue_runner(): void {
		if ( ! Background_Runtime_State::is_enabled() || ! Universal_Data_Migration::instance()->is_ready() ) {
			return;
		}
		Store_Queue_Runner::instance()->register();
	}

    private function register_autoload(): void {
        // All plugin PHP files are loaded via includes/load.php (required from main plugin file).
    }

    private function init_admin(): void {
        Admin::instance()->init();
        Settings_Page::instance()->init();
        Studio_Page::instance()->init();
        Modules_Registry::instance()->init();
    }

    private function init_rest(): void {
        add_action( 'rest_api_init', function (): void {
            fotogenic_ai_load_rest_bucket();
            Rest::instance()->init();
        }, 0 );
    }

    private function register_activation_checks(): void {
        register_activation_hook( FOTOGENIC_AI_FILE, [ $this, 'activation_check' ] );
        register_deactivation_hook( FOTOGENIC_AI_FILE, [ $this, 'deactivation_cleanup' ] );
    }

	private function register_platform_diagnostics(): void {
		add_action( 'admin_notices', [ $this, 'render_platform_notice' ] );
		add_filter( 'site_status_tests', [ $this, 'add_site_health_tests' ] );
	}

	public function render_platform_notice(): void {
		$messages = [];
		$site = $this->capabilities()->activation_status( false );
		if ( ! $site['available'] ) {
			$messages[] = $site['message'];
		} else {
			$stored = get_option( Auth_Session::OPTION_NAME, [] );
			$payload = is_array( $stored ) ? trim( (string) ( $stored['refreshToken'] ?? '' ) ) : '';
			$crypto = $this->capabilities()->crypto_status( $payload );
			if ( ! $crypto['available'] || ! $crypto['readable'] ) {
				$messages[] = $crypto['message'];
			}
			$woocommerce = $this->capabilities()->woocommerce_status();
			if ( ! $woocommerce['available'] && 'woocommerce_absent' !== $woocommerce['code'] ) {
				$messages[] = $woocommerce['message'];
			}
		}
		foreach ( array_values( array_unique( array_filter( $messages ) ) ) as $message ) {
			?>
			<div class="notice notice-warning"><p><?php echo esc_html( $message ); ?></p></div>
			<?php
		}
	}

	public function add_site_health_tests( array $tests ): array {
		$tests['direct']['fotogenic_ai_site_topology'] = [
			'label' => __( 'Fotogenic AI site topology', 'fotogenic-ai' ),
			'test'  => [ $this, 'test_site_topology' ],
		];
		$tests['direct']['fotogenic_ai_crypto'] = [
			'label' => __( 'Fotogenic AI login encryption', 'fotogenic-ai' ),
			'test'  => [ $this, 'test_crypto_readiness' ],
		];
		$tests['direct']['fotogenic_ai_woocommerce'] = [
			'label' => __( 'Fotogenic AI WooCommerce compatibility', 'fotogenic-ai' ),
			'test'  => [ $this, 'test_woocommerce_readiness' ],
		];
		$tests['direct']['fotogenic_ai_bulk_storage'] = [
			'label' => __( 'Fotogenic AI Bulk storage', 'fotogenic-ai' ),
			'test'  => [ $this, 'test_bulk_storage_readiness' ],
		];

		return $tests;
	}

	public function test_site_topology(): array {
		$status = $this->capabilities()->activation_status( false );
		return $this->site_health_result(
			$status['available'],
			__( 'Fotogenic AI is running on a supported single site.', 'fotogenic-ai' ),
			$status['message'],
			'fotogenic_ai_site_topology'
		);
	}

	public function test_crypto_readiness(): array {
		$stored = get_option( Auth_Session::OPTION_NAME, [] );
		$payload = is_array( $stored ) ? trim( (string) ( $stored['refreshToken'] ?? '' ) ) : '';
		$status = $this->capabilities()->crypto_status( $payload );
		$ready = $status['available'] && $status['readable'];
		return $this->site_health_result(
			$ready,
			__( 'Fotogenic AI login encryption is available.', 'fotogenic-ai' ),
			$status['message'],
			'fotogenic_ai_crypto'
		);
	}

	public function test_woocommerce_readiness(): array {
		$status = $this->capabilities()->woocommerce_status();
		$ready_or_optional = $status['available'] || 'woocommerce_absent' === $status['code'];
		$good = $status['available']
			? __( 'WooCommerce Product sources are available.', 'fotogenic-ai' )
			: __( 'WooCommerce is optional; Media, Post, and Page sources remain available.', 'fotogenic-ai' );
		return $this->site_health_result(
			$ready_or_optional,
			$good,
			$status['message'],
			'fotogenic_ai_woocommerce'
		);
	}

	public function test_bulk_storage_readiness(): array {
		$status = Bulk_Repo::instance()->transactional_storage_status();
		return $this->site_health_result(
			$status['available'],
			__( 'Fotogenic AI Bulk storage uses InnoDB transactions.', 'fotogenic-ai' ),
			$status['message'],
			'fotogenic_ai_bulk_storage'
		);
	}

	private function site_health_result( bool $good, string $good_message, string $problem_message, string $test ): array {
		$message = $good ? $good_message : $problem_message;
		return [
			'label'       => $message,
			'status'      => $good ? 'good' : 'critical',
			'badge'       => [
				'label' => __( 'Fotogenic AI', 'fotogenic-ai' ),
				'color' => 'blue',
			],
			'description' => '<p>' . esc_html( $message ) . '</p>',
			'actions'     => '',
			'test'        => $test,
		];
	}

    private function schedule_log_purge(): void {
		if ( ! Background_Runtime_State::is_enabled() ) {
			return;
		}
		if ( ! wp_next_scheduled( 'fotogenic_ai_log_purge' ) ) {
            wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'fotogenic_ai_log_purge' );
        }
		if ( ! Background_Runtime_State::is_enabled() ) {
			wp_unschedule_hook( 'fotogenic_ai_log_purge' );
		}
    }

	private function schedule_store_queue_purge(): void {
		if ( ! Background_Runtime_State::is_enabled() ) {
			return;
		}
		if ( ! wp_next_scheduled( self::STORE_QUEUE_PURGE_HOOK ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', self::STORE_QUEUE_PURGE_HOOK );
		}
	}

    public function register_privacy_policy_content(): void {
        if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
            return;
        }

        $privacy_link = sprintf(
            '<a href="%s">%s</a>',
            esc_url( Settings_Page::get_privacy_policy_url() ),
            esc_html__( 'Fotogenic.ai Privacy Policy', 'fotogenic-ai' )
        );

        $content  = '<p>' . esc_html__( 'Fotogenic AI communicates with the external Fotogenic.ai service only when an administrator uses connected features such as account login, configuration refresh, credits lookup, or image generation.', 'fotogenic-ai' ) . '</p>';
        $content .= '<p>' . esc_html__( 'When those features are used, the plugin may send selected source images, prompts or custom instructions, generation settings, job identifiers, and minimal target metadata required to complete the request.', 'fotogenic-ai' ) . '</p>';
        $content .= '<p>' . esc_html__( 'The plugin stores plugin settings, an encrypted Fotogenic session token pair, cached configuration data, generation history, and local debug log entries in WordPress.', 'fotogenic-ai' ) . '</p>';
        /* translators: %s: external privacy policy link. */
        $privacy_text = __( 'For the service-side privacy policy, review the %s.', 'fotogenic-ai' );
        $content .= '<p>' . sprintf(
            wp_kses(
                $privacy_text,
                [ 'a' => [ 'href' => [] ] ]
            ),
            $privacy_link
        ) . '</p>';

        wp_add_privacy_policy_content(
            __( 'Fotogenic AI', 'fotogenic-ai' ),
            wp_kses_post( $content )
        );
    }

    public function activation_check( bool $network_wide = false ): void {
		$platform = $this->capabilities()->activation_status( $network_wide );
		if ( ! $platform['available'] ) {
			$this->reject_activation( $platform['message'], $network_wide );
		}
        global $wp_version;
		$runtime = $this->capabilities()->runtime_status( PHP_VERSION, (string) $wp_version );
		if ( ! $runtime['available'] ) {
			$this->reject_activation( $runtime['message'], $network_wide );
		}

		$this->begin_background_activation();

        $settings = Settings::instance();
        if ( false === get_option( $settings->get_option_name(), false ) ) {
            add_option( $settings->get_option_name(), $settings->get_defaults(), '', false );
        }
        if ( ! Universal_Data_Migration::instance()->run( true ) ) {
            $this->deactivate_with_message(
                __( 'Fotogenic AI could not safely upgrade its stored Studio data. No generation was started.', 'fotogenic-ai' )
            );
        }
        $this->schedule_bulk_housekeeping();
		$this->complete_background_activation();
        // WooCommerce is optional; when present, integrate. No deactivation when WC is missing.
    }

	private function begin_background_activation(): void {
		remove_action( 'action_scheduler_init', [ $this, 'deactivation_action_scheduler_cleanup' ], PHP_INT_MAX );
		Background_Runtime_State::enable();
		Background_Scheduler::instance()->activation_cleanup();
	}

	private function complete_background_activation(): void {
		Background_Finalizer::instance()->activation_cleanup();
	}

    /**
     * Seed the bounded Bulk maintenance loop when the plugin is activated.
     */
    private function schedule_bulk_housekeeping(): void {
		if ( ! Background_Runtime_State::is_enabled() || false !== wp_next_scheduled( Service_Bulk::HOUSEKEEPING_HOOK ) ) {
            return;
        }

        wp_schedule_single_event(
            time() + self::BULK_HOUSEKEEPING_INITIAL_DELAY,
            Service_Bulk::HOUSEKEEPING_HOOK
        );
		if ( ! Background_Runtime_State::is_enabled() ) {
			wp_unschedule_hook( Service_Bulk::HOUSEKEEPING_HOOK );
		}
    }

    /**
     * Unschedule plugin jobs on deactivation.
     */
    public function deactivation_cleanup(): void {
		Background_Runtime_State::disable();
        wp_unschedule_hook( 'fotogenic_ai_log_purge' );
		wp_unschedule_hook( self::STORE_QUEUE_PURGE_HOOK );
        wp_unschedule_hook( Auth_Session::CRON_HOOK );
        wp_unschedule_hook( Service_Bulk::HOUSEKEEPING_HOOK );
		wp_unschedule_hook( Result_Delivery_Coordinator::HOOK_RETRY );
		Bulk_Scheduler::instance()->deactivation_cleanup();
		Store_Queue_Scheduler::instance()->deactivation_cleanup();
		Background_Finalizer::instance()->deactivation_cleanup();

		if ( ! function_exists( 'as_unschedule_all_actions' ) ) {
			return;
		}
		if ( Background_Scheduler::instance()->has_action_scheduler() ) {
			$this->deactivation_action_scheduler_cleanup();
			return;
		}
		remove_action( 'action_scheduler_init', [ $this, 'deactivation_action_scheduler_cleanup' ], PHP_INT_MAX );
		add_action( 'action_scheduler_init', [ $this, 'deactivation_action_scheduler_cleanup' ], PHP_INT_MAX );
    }

	/**
	 * Remove plugin-owned Action Scheduler work after its store is initialized.
	 */
	public function deactivation_action_scheduler_cleanup(): void {
		if ( ! Background_Scheduler::instance()->has_action_scheduler() || ! function_exists( 'as_unschedule_all_actions' ) ) {
			return;
		}
		remove_action( 'action_scheduler_init', [ $this, 'deactivation_action_scheduler_cleanup' ], PHP_INT_MAX );
		Bulk_Scheduler::instance()->deactivation_action_scheduler_cleanup();
		Store_Queue_Scheduler::instance()->deactivation_cleanup();
		Background_Scheduler::instance()->deactivation_action_scheduler_cleanup();
		as_unschedule_all_actions( Result_Delivery_Coordinator::HOOK_RETRY );
    }

    private function deactivate_with_message( string $message ): void {
		$this->deactivation_cleanup();
        deactivate_plugins( plugin_basename( FOTOGENIC_AI_FILE ) );
        wp_die( esc_html( $message ), esc_html__( 'Fotogenic AI', 'fotogenic-ai' ), [ 'back_link' => true ] );
    }

	/**
	 * Reject an unsupported topology before any plugin-owned state is mutated.
	 */
	private function reject_activation( string $message, bool $network_wide ): void {
		deactivate_plugins( plugin_basename( FOTOGENIC_AI_FILE ), true, $network_wide );
		wp_die( esc_html( $message ), esc_html__( 'Fotogenic AI', 'fotogenic-ai' ), [ 'back_link' => true ] );
	}
}
