<?php
/**
 * PDF Designs REST API controller.
 *
 * @package PDFDraft
 */

namespace PDFDraft\Controllers\V1;

use PDFDraft\Contracts\Services\ImageServiceInterface;
use PDFDraft\Services\StorageService;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Handles REST API requests for PDF design posts.
 */
class PDFDesignsController extends \WP_REST_Posts_Controller {

	/**
	 * Image service instance.
	 *
	 * @var ImageServiceInterface
	 */
	private ImageServiceInterface $imageService;

	/**
	 * Constructor.
	 *
	 * @param string                $post_type    Post type slug.
	 * @param ImageServiceInterface $imageService Image service dependency.
	 */
	public function __construct( $post_type, ImageServiceInterface $imageService ) {
		parent::__construct( $post_type );
		$this->imageService = $imageService;
		add_action( "rest_after_insert_{$this->post_type}", array( $this, 'processPreviewImage' ), 10, 2 );
	}

	/**
	 * Whether the WooCommerce invoices add-on is loaded (filter supplied by that plugin).
	 *
	 * @return bool
	 */
	protected function is_woocommerce_invoices_addon_active(): bool {
		return (bool) apply_filters( 'pdfdraft_is_woocommerce_invoices_addon_active', false );
	}

	/**
	 * Detect designs created for or assigned to WooCommerce invoice templates.
	 *
	 * @param \WP_Post $post Design post.
	 * @return bool
	 */
	protected function post_is_woocommerce_invoice_design( $post ): bool {
		$flag = get_post_meta( $post->ID, 'pdfdraft_for', true );
		if ( 'woo' === $flag ) {
			return true;
		}
		// Legacy: slug still stored as the WooCommerce active template option.
		$legacy = get_option( 'pdfdraft_pdf_invoices_for_woocommerce_active_design_slug', '' );
		return is_string( $legacy ) && '' !== $legacy && $post->post_name === $legacy;
	}

	/**
	 * Block loading or updating Woo invoice designs when the add-on is not active.
	 *
	 * @param \WP_Post $post Design post.
	 * @return true|\WP_Error
	 */
	protected function guard_woocommerce_invoice_design_without_addon( $post ) {
		if ( ! $this->post_is_woocommerce_invoice_design( $post ) ) {
			return true;
		}
		if ( $this->is_woocommerce_invoices_addon_active() ) {
			return true;
		}
		return new \WP_Error(
			'pdfdraft_woo_addon_required',
			__( 'This design is for WooCommerce invoices. Activate PDFDraft PDF Invoices for WooCommerce to edit it.', 'pdfdraft' ),
			array( 'status' => 403 )
		);
	}

	/**
	 * Retrieves a single PDF design; blocks Woo invoice designs in edit context without the add-on.
	 *
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return \WP_REST_Response|\WP_Error Response or error.
	 */
	public function get_item( $request ) {
		$post = $this->get_post( $request['id'] );
		if ( is_wp_error( $post ) ) {
			return $post;
		}
		$context = $request->get_param( 'context' );
		if ( ! is_string( $context ) || '' === $context ) {
			$context = 'view';
		}
		if ( 'edit' === $context ) {
			$blocked = $this->guard_woocommerce_invoice_design_without_addon( $post );
			if ( is_wp_error( $blocked ) ) {
				return $blocked;
			}
		}
		return parent::get_item( $request );
	}

	/**
	 * Updates a single PDF design; blocks Woo invoice designs without the add-on.
	 *
	 * Normalises $request['id'] to a numeric post ID before delegating to the
	 * parent so that WordPress core methods (get_post_type, get_post_type_object,
	 * handle_status_param, etc.) receive a value they can look up correctly.
	 * Without this, slug-based IDs cause get_post_type() to return false, which
	 * propagates to a null post-type object and a bogus 403 / corrupted post_type.
	 *
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return \WP_REST_Response|\WP_Error Response or error.
	 */
	public function update_item( $request ) {
		$post = $this->get_post( $request['id'] );
		if ( is_wp_error( $post ) ) {
			return $post;
		}
		$blocked = $this->guard_woocommerce_invoice_design_without_addon( $post );
		if ( is_wp_error( $blocked ) ) {
			return $blocked;
		}
		$request['id'] = $post->ID;
		return parent::update_item( $request );
	}

	/**
	 * Register REST API routes for PDF designs.
	 *
	 * @return void
	 */
	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_items' ),
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
					'args'                => $this->get_collection_params(),
				),
				array(

					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_item' ),
					'permission_callback' => array( $this, 'create_item_permissions_check' ),
					'args'                => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),

				),
				'allow_batch' => $this->allow_batch,
				'schema'      => array( $this, 'get_public_item_schema' ),
			)
		);
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/suggest-name',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'suggest_name' ),
				'permission_callback' => array( $this, 'create_item_permissions_check' ),
				'args'                => array(
					'name' => array(
						'type'              => 'string',
						'required'          => true,
						'maxLength'         => 200,
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);
		register_rest_route(
			$this->namespace,
			"/{$this->rest_base}/(?P<id>[\w-]+)",
			array(
				'args'        => array(
					'id' => array(
						'description' => __( 'Unique identifier for the post.', 'pdfdraft' ),
						'type'        => 'string',
					),
				),
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_item' ),
					'permission_callback' => array( $this, 'get_item_permissions_check' ),
					'args'                => array(
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					),
				),
				array(
					'methods'             => \WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_item' ),
					'permission_callback' => array( $this, 'update_item_permissions_check' ),
					'args'                => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE ),
				),
				array(
					'methods'             => \WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_item' ),
					'permission_callback' => array( $this, 'delete_item_permissions_check' ),
					'args'                => array(
						'force' => array(
							'type'        => 'boolean',
							'default'     => false,
							'description' => __( 'Whether to bypass Trash and force deletion.', 'pdfdraft' ),
						),
						'for'   => array(
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						),
					),
				),
				'allow_batch' => $this->allow_batch,
				'schema'      => array( $this, 'get_public_item_schema' ),
			)
		);
	}

	/**
	 * Gets the post, if the ID or slug is valid.
	 *
	 * Overrides base method to allow param $id to be ID or slug.
	 *
	 * @param int|string $id Supplied ID or slug.
	 * @return \WP_Post|\WP_Error Post object if ID or slug is valid, WP_Error otherwise.
	 */
	protected function get_post( $id ) {
		$error = new \WP_Error(
			'rest_post_invalid_id',
			__( 'Invalid post ID or slug.', 'pdfdraft' ),
			array( 'status' => 404 )
		);

		if ( is_numeric( $id ) && (int) $id > 0 ) {
			$post = get_post( (int) $id );
		} else {
			$query = new \WP_Query(
				array(
					'name'           => $id,
					'post_type'      => $this->post_type,
					'posts_per_page' => 1,
					// Draft and publish.
					'post_status'    => 'any',
				)
			);
			$post  = current( $query->posts );
		}

		if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
			return $error;
		}

		return $post;
	}

	/**
	 * Prepare a PDF design for response with decoded JSON content.
	 *
	 * @param \WP_Post         $item    Post object.
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return \WP_REST_Response Response object.
	 */
	public function prepare_item_for_response( $item, $request ) {
		$response             = parent::prepare_item_for_response( $item, $request );
		$data                 = $response->get_data();
		$data['content']      = json_decode( $data['content']['raw'] ?? '{}' );
		$data['previewImage'] = $this->imageService->getUrl( $data['slug'] );
		$data['hasEmbedPdf']  = pdfdraft( StorageService::class )->fileExists( 'projects/' . $data['slug'] . '.pdf' );
		$response->set_data( $data );
		return $response;
	}

	/**
	 * Process preview image after post insert.
	 *
	 * @param \WP_Post         $post    Inserted post object.
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return void
	 */
	public function processPreviewImage( $post, $request ) {
		$requestData = is_array( $request ) ? $request : $request->get_params();
		$this->imageService->storeFromRequest( $post, $requestData );
	}

	/**
	 * Prepare query arguments with orientation meta filter.
	 *
	 * @param array            $prepared_args Optional prepared arguments.
	 * @param \WP_REST_Request $request       Full details about the request.
	 * @return array Modified query arguments.
	 */
	protected function prepare_items_query( $prepared_args = array(), $request = null ) {
		$query_args = parent::prepare_items_query( $prepared_args, $request );
		if ( ! $request instanceof \WP_REST_Request ) {
			return $query_args;
		}
		$orientation = $request->get_param( 'orientation' );
		if ( ! is_string( $orientation ) || ! in_array( $orientation, array( 'landscape', 'portrait' ), true ) ) {
			return $query_args;
		}
		if ( ! isset( $query_args['meta_query'] ) || ! is_array( $query_args['meta_query'] ) ) {
			$query_args['meta_query'] = array();
		}
		$query_args['meta_query'][] = array(
			'key'     => 'orientation',
			'value'   => $orientation,
			'compare' => '=',
		);
		return $query_args;
	}

	/**
	 * Retrieve PDF designs with post counts header.
	 *
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return \WP_REST_Response Response object.
	 */
	public function get_items( $request ) {
		$response = parent::get_items( $request );
		$response->header( 'X-WP-Counts', wp_json_encode( (array) wp_count_posts( $this->post_type ) ) );
		return $response;
	}

	/**
	 * Suggest the next available design name based on an existing base name.
	 *
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return \WP_REST_Response Response with suggested name.
	 */
	public function suggest_name( \WP_REST_Request $request ): \WP_REST_Response {
		global $wpdb;

		$base      = (string) $request->get_param( 'name' );
		$author_id = get_current_user_id();

		$rows = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT post_title FROM {$wpdb->posts}
				 WHERE post_type = %s
				 AND post_author = %d
				 AND post_status NOT IN ('trash', 'auto-draft')
				 AND ( post_title = %s OR post_title LIKE %s )",
				$this->post_type,
				$author_id,
				$base,
				$wpdb->esc_like( $base ) . ' (%)'
			)
		);

		$pattern   = '/^' . preg_quote( $base, '/' ) . ' \((\d+)\)$/';
		$has_exact = false;
		$max_num   = 0;

		foreach ( $rows as $title ) {
			if ( $title === $base ) {
				$has_exact = true;
			} elseif ( preg_match( $pattern, $title, $matches ) ) {
				$max_num = max( $max_num, (int) $matches[1] );
			}
		}

		$suggested = ( $has_exact || $max_num > 0 )
			? $base . ' (' . ( $max_num + 1 ) . ')'
			: $base;

		return new \WP_REST_Response( array( 'name' => $suggested ), 200 );
	}

	/**
	 * Delete a PDF design and fire cleanup action.
	 *
	 * @param \WP_REST_Request $request Full details about the request.
	 * @return \WP_REST_Response|\WP_Error Response object or error.
	 */
	public function delete_item( $request ) {
		$response = parent::delete_item( $request );
		if ( ! is_wp_error( $response ) && $response->get_status() >= 200 && $response->get_status() < 300 ) {
			do_action( 'pdfdraft_after_delete_pdf_design', $request );
		}
		return $response;
	}
}
