<?php
/**
 * Document REST — GET/POST JSON, never raw HTML as source of truth.
 *
 * @package AuraBuilder
 */

declare(strict_types=1);

namespace AuraBuilder\REST;

use AuraBuilder\Admin\HomePageBridge;
use AuraBuilder\Document\DocumentSanitizer;
use AuraBuilder\Import\ContentImporter;
use AuraBuilder\Renderer\DocumentRenderer;
use AuraBuilder\Storage\DocumentRepository;
use AuraBuilder\Theme\ThemeChrome;
use AuraBuilder\Widgets\Basic\PopupWidget;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

final class DocumentsController {

	private DocumentRepository $repo;
	private DocumentRenderer $renderer;

	public function __construct() {
		$this->repo     = new DocumentRepository();
		$this->renderer = new DocumentRenderer();
	}

	public function register( string $ns ): void {
		register_rest_route(
			$ns,
			'/documents/(?P<id>\d+)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_item' ),
					'permission_callback' => array( $this, 'can_edit' ),
				),
				array(
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_item' ),
					'permission_callback' => array( $this, 'can_update' ),
				),
			)
		);

		register_rest_route(
			$ns,
			'/documents/(?P<id>\d+)/render',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'render' ),
				'permission_callback' => array( $this, 'can_edit' ),
			)
		);

		register_rest_route(
			$ns,
			'/documents/(?P<id>\d+)/import',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'import_item' ),
				'permission_callback' => array( $this, 'can_edit' ),
			)
		);
	}

	/**
	 * Read access: edit the target post.
	 *
	 * @return true|WP_Error
	 */
	public function can_edit( WP_REST_Request $req ) {
		$id = (int) $req['id'];
		if ( $id <= 0 || ! \AuraBuilder\Support\Capabilities::can_edit_post( $id ) ) {
			return new WP_Error(
				'ab_forbidden',
				__( 'Sem permissão para editar este documento. Faça login novamente no wp-admin e reabra o editor.', 'auranet-page-theme-builder' ),
				array( 'status' => 403 )
			);
		}
		return true;
	}

	/**
	 * Whether the user may change site-wide options (home page, global popups).
	 */
	private function can_manage_site_builder_options(): bool {
		return \AuraBuilder\Support\Capabilities::can_manage_settings()
			|| current_user_can( 'edit_theme_options' );
	}

	/**
	 * Update may also change site homepage / global popups — require stronger caps for those side-effects.
	 *
	 * @return true|WP_Error
	 */
	public function can_update( WP_REST_Request $req ) {
		$ok = $this->can_edit( $req );
		if ( is_wp_error( $ok ) ) {
			return $ok;
		}
		$body = $req->get_json_params();
		if ( ! is_array( $body ) ) {
			return true;
		}
		$doc      = is_array( $body['document'] ?? null ) ? $body['document'] : array();
		$settings = is_array( $doc['settings'] ?? null ) ? $doc['settings'] : array();

		// Setting as homepage touches site-wide Reading options.
		if ( ! empty( $settings['is_home_page'] ) && ! $this->can_manage_site_builder_options() ) {
			return new WP_Error(
				'aptb_forbidden_home',
				__( 'Sem permissão para definir a página inicial.', 'auranet-page-theme-builder' ),
				array( 'status' => 403 )
			);
		}

		// Popups with scope home/all write to a site-wide option (aptb_site_popups).
		if ( $this->document_has_sitewide_popups( $doc ) && ! $this->can_manage_site_builder_options() ) {
			return new WP_Error(
				'aptb_forbidden_popups',
				__( 'Sem permissão para sincronizar popups globais do site.', 'auranet-page-theme-builder' ),
				array( 'status' => 403 )
			);
		}

		return true;
	}

	/**
	 * @param array<string, mixed> $doc Raw document array from request.
	 */
	private function document_has_sitewide_popups( array $doc ): bool {
		$nodes = is_array( $doc['nodes'] ?? null ) ? $doc['nodes'] : array();
		foreach ( $nodes as $node ) {
			if ( ! is_array( $node ) ) {
				continue;
			}
			$type = (string) ( $node['type'] ?? '' );
			if ( $type !== 'popup' ) {
				continue;
			}
			$settings = is_array( $node['settings'] ?? null ) ? $node['settings'] : array();
			$scope    = sanitize_key( (string) ( $settings['scope'] ?? 'current' ) );
			if ( $scope === 'home' || $scope === 'all' ) {
				return true;
			}
		}
		return false;
	}

	public function get_item( WP_REST_Request $req ): WP_REST_Response {
		$id   = (int) $req['id'];
		$meta = $this->repo->get_with_meta( $id );
		$doc  = $meta['document'];
		$out  = $this->renderer->render( $doc, array( 'editor' => true ) );
		$chrome = ( new ThemeChrome() )->parts();

		return new WP_REST_Response(
			array(
				'postId'   => $id,
				'title'    => get_the_title( $id ),
				'enabled'  => $this->repo->is_enabled( $id ),
				'document' => $doc->to_array(),
				'html'     => $out['html'],
				'css'      => $out['css'],
				'viewUrl'  => get_permalink( $id ),
				'editUrl'  => get_edit_post_link( $id, 'raw' ),
				'nonce'    => wp_create_nonce( 'wp_rest' ),
				'source'   => $meta['source'],
				'imported' => $meta['imported'],
				'theme'    => $chrome,
			)
		);
	}

	public function update_item( WP_REST_Request $req ): WP_REST_Response|WP_Error {
		$id   = (int) $req['id'];
		$body = $req->get_json_params();
		if ( ! is_array( $body ) || empty( $body['document'] ) || ! is_array( $body['document'] ) ) {
			return new WP_Error( 'ab_invalid', 'Documento inválido', array( 'status' => 400 ) );
		}

		$enable = ! isset( $body['enabled'] ) || (bool) $body['enabled'];
		$doc    = DocumentSanitizer::sanitize( $body['document'] );
		$saved  = $this->repo->save( $id, $doc, $enable );

		// Site-wide side effects only when the user has theme/site management caps
		// (permission_callback already enforces this when needed).
		if ( $this->can_manage_site_builder_options() ) {
			$this->sync_global_popups( $id, $saved );
			$is_home = ! empty( $saved->settings['is_home_page'] );
			HomePageBridge::set_as_home( $id, (bool) $is_home );
		}

		$out = $this->renderer->render( $saved, array( 'editor' => true ) );

		return new WP_REST_Response(
			array(
				'ok'       => true,
				'document' => $saved->to_array(),
				'enabled'  => true,
				'html'     => $out['html'],
				'css'      => $out['css'],
				'nonce'    => wp_create_nonce( 'wp_rest' ),
			)
		);
	}

	/**
	 * Sync popup widgets with scope home/all into a site-wide option.
	 */
	private function sync_global_popups( int $post_id, \AuraBuilder\Document\Document $doc ): void {
		$option_key = 'aptb_site_popups';
		$existing   = get_option( $option_key, array() );
		if ( ! is_array( $existing ) ) {
			$existing = array();
		}
		// Remove previous entries from this post.
		$existing = array_values(
			array_filter(
				$existing,
				static function ( $row ) use ( $post_id ) {
					return ! is_array( $row ) || (int) ( $row['post_id'] ?? 0 ) !== $post_id;
				}
			)
		);
		foreach ( $doc->nodes as $node ) {
			if ( $node->type !== 'popup' ) {
				continue;
			}
			$cfg = PopupWidget::public_config( $node );
			if ( ! $cfg ) {
				continue;
			}
			$scope = (string) ( $cfg['scope'] ?? 'current' );
			if ( $scope !== 'home' && $scope !== 'all' ) {
				continue;
			}
			$cfg['post_id'] = $post_id;
			$existing[]     = $cfg;
		}
		// Cap size.
		if ( count( $existing ) > 20 ) {
			$existing = array_slice( $existing, -20 );
		}
		update_option( $option_key, $existing, false );
	}

	public function render( WP_REST_Request $req ): WP_REST_Response|WP_Error {
		$body = $req->get_json_params();
		if ( ! is_array( $body ) || empty( $body['document'] ) || ! is_array( $body['document'] ) ) {
			return new WP_Error( 'ab_invalid', 'Documento inválido', array( 'status' => 400 ) );
		}
		$doc = DocumentSanitizer::sanitize( $body['document'] );
		$out = $this->renderer->render( $doc, array( 'editor' => ! empty( $body['editor'] ) ) );
		return new WP_REST_Response( $out );
	}

	/**
	 * Force re-import from Elementor / HTML (does not auto-save).
	 */
	public function import_item( WP_REST_Request $req ): WP_REST_Response {
		$id  = (int) $req['id'];
		// Clear saved builder doc so next get would reimport; here we import live without requiring clear.
		delete_post_meta( $id, AURA_BUILDER_META_DOC );
		update_post_meta( $id, AURA_BUILDER_META_ON, '0' );

		$doc = ( new ContentImporter() )->from_post( $id );
		$out = $this->renderer->render( $doc, array( 'editor' => true ) );

		return new WP_REST_Response(
			array(
				'document' => $doc->to_array(),
				'html'     => $out['html'],
				'css'      => $out['css'],
				'source'   => (string) ( $doc->metadata['importedFrom'] ?? 'import' ),
				'imported' => true,
			)
		);
	}
}
