<?php

/**
 * AJAX endpoints for the built-plugins library list table.
 *
 * @package LolaCore\PluginBuilder\Admin
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\PluginBuilder\Admin;

use LolaCore\I18n\ErrorMessages;
use LolaCore\PluginBuilder\Gate\PlaygroundGate;
use LolaCore\PluginBuilder\Packaging\LocalInstaller;
use LolaCore\PluginBuilder\Playground\BlueprintGenerator;
use LolaCore\PluginBuilder\PostType\PluginPostType;

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

/**
 * Playground URL and local install actions from the library screen.
 */
class PluginBuilderAjax {

	private BlueprintGenerator $blueprintGenerator;
	private LocalInstaller $localInstaller;

	public function __construct(
		?BlueprintGenerator $blueprintGenerator = null,
		?LocalInstaller $localInstaller = null
	) {
		$this->blueprintGenerator = $blueprintGenerator ?? new BlueprintGenerator();
		$this->localInstaller     = $localInstaller ?? new LocalInstaller();
	}

	/**
	 * Register wp_ajax handlers.
	 */
	public function register(): void {
		add_action('wp_ajax_lolacore_pb_playground', array($this, 'handlePlayground'));
		add_action('wp_ajax_lolacore_pb_playground_opened', array($this, 'handlePlaygroundOpened'));
		add_action('wp_ajax_lolacore_pb_playground_attest', array($this, 'handlePlaygroundAttest'));
		add_action('wp_ajax_lolacore_pb_install', array($this, 'handleInstall'));
		add_action('wp_ajax_lolacore_pb_activate', array($this, 'handleActivate'));
	}

	/**
	 * Return a Playground URL for the library entry (opens in a new tab client-side).
	 */
	public function handlePlayground(): void {
		$this->verifySecurity();

		$post_id = $this->readPostId();
		if ($post_id <= 0) {
			wp_send_json_error(array('message' => __('Invalid plugin ID.', 'lolacore')), 400);
		}

		$this->assertBuiltPluginPost($post_id);

		try {
			$url  = $this->blueprintGenerator->build($post_id);
			$post = get_post($post_id);
			$name = $post instanceof \WP_Post ? $post->post_title : '';

			wp_send_json_success(
				array_merge(
					array(
						'playground_url' => $url,
						'post_id'        => $post_id,
						'name'           => $name,
						'slug'           => (string) get_post_meta($post_id, PluginPostType::META_SLUG, true),
					),
					PlaygroundGate::uiFlags($post_id)
				)
			);
		} catch (\Throwable $e) {
			wp_send_json_error(array('message' => $e->getMessage()), 500);
		}
	}

	/**
	 * Record that the user opened Playground (chat or library UI).
	 */
	public function handlePlaygroundOpened(): void {
		$this->verifySecurity();

		$post_id = $this->readPostId();
		if ($post_id <= 0) {
			wp_send_json_error(array('message' => __('Invalid plugin ID.', 'lolacore')), 400);
		}

		$this->assertBuiltPluginPost($post_id);
		PlaygroundGate::markOpened($post_id);

		wp_send_json_success(PlaygroundGate::uiFlags($post_id));
	}

	/**
	 * Record Playground attestation outcome (ready to install or issues found).
	 */
	public function handlePlaygroundAttest(): void {
		$this->verifySecurity();

		$post_id = $this->readPostId();
		if ($post_id <= 0) {
			wp_send_json_error(array('message' => __('Invalid plugin ID.', 'lolacore')), 400);
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified in verifySecurity().
		$outcome = isset($_POST['outcome']) ? sanitize_key((string) wp_unslash($_POST['outcome'])) : '';

		$this->assertBuiltPluginPost($post_id);

		if ($outcome === 'attested') {
			PlaygroundGate::markAttested($post_id);
		} elseif ($outcome === 'failed') {
			PlaygroundGate::markFailed($post_id);
		} else {
			wp_send_json_error(array('message' => __('Invalid attestation outcome.', 'lolacore')), 400);
		}

		wp_send_json_success(PlaygroundGate::uiFlags($post_id));
	}

	/**
	 * Install the built plugin on this site (with optional overwrite).
	 */
	public function handleInstall(): void {
		$this->verifySecurity();

		$post_id = $this->readPostId();
		if ($post_id <= 0) {
			wp_send_json_error(array('message' => __('Invalid plugin ID.', 'lolacore')), 400);
		}

		$this->assertBuiltPluginPost($post_id);

		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified in verifySecurity().
		$overwrite = ! empty($_POST['overwrite']);

		if (! $overwrite && $this->localInstaller->isAlreadyInstalled($post_id)) {
			wp_send_json_error(
				array(
					'message'         => __('A version is already installed. Overwrite it?', 'lolacore'),
					'needs_overwrite' => true,
				),
				409
			);
		}

		try {
			PlaygroundGate::assertInstallAllowed($post_id);
			PlaygroundGate::assertLoadSafe($post_id);
			$result = $this->localInstaller->install($post_id, $overwrite);

			wp_send_json_success(
				array(
					'message'       => (string) ( $result['message'] ?? '' ),
					'post_id'       => $post_id,
					'plugin_file'   => (string) ( $result['plugin_file'] ?? '' ),
					'activated'     => (bool) ( $result['activated'] ?? false ),
					'overwritten'   => (bool) ( $result['overwritten'] ?? false ),
					'plugins_url'   => admin_url('plugins.php'),
					'can_activate'  => ! (bool) ( $result['activated'] ?? false ),
				)
			);
		} catch (\Throwable $e) {
			$payload = array('message' => $e->getMessage());

			// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified in verifySecurity().
			if (! $overwrite && $this->localInstaller->isAlreadyInstalled($post_id)) {
				$payload['needs_overwrite'] = true;
			}

			wp_send_json_error($payload, 500);
		}
	}

	/**
	 * Activate a built plugin that is already on disk (explicit user choice).
	 */
	public function handleActivate(): void {
		$this->verifySecurity();

		$post_id = $this->readPostId();
		if ($post_id <= 0) {
			wp_send_json_error(array('message' => __('Invalid plugin ID.', 'lolacore')), 400);
		}

		$this->assertBuiltPluginPost($post_id);

		try {
			$result = $this->localInstaller->activateInstalled($post_id);

			wp_send_json_success(
				array(
					'message'     => (string) ( $result['message'] ?? '' ),
					'post_id'     => $post_id,
					'plugin_file' => (string) ( $result['plugin_file'] ?? '' ),
					'activated'   => true,
				)
			);
		} catch (\Throwable $e) {
			wp_send_json_error(array('message' => $e->getMessage()), 500);
		}
	}

	private function verifySecurity(): void {
		if (! check_ajax_referer('lolacore_admin_nonce', '_ajax_nonce', false)) {
			wp_send_json_error(array('message' => ErrorMessages::sessionExpired()), 403);
		}

		if (! current_user_can('manage_options')) {
			wp_send_json_error(array('message' => ErrorMessages::unauthorized()), 403);
		}
	}

	private function readPostId(): int {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified in verifySecurity().
		return isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
	}

	private function assertBuiltPluginPost( int $post_id ): void {
		$post = get_post($post_id);
		if (! $post instanceof \WP_Post || $post->post_type !== PluginPostType::POST_TYPE) {
			wp_send_json_error(array('message' => __('Built plugin not found.', 'lolacore')), 404);
		}
	}
}
