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

namespace PDFDraft\PostsToPdf;

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

use PDFDraft\PostsToPdf\Settings as PostsToPdfSettings;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

/**
 * Handles REST API endpoints for the Posts to PDF feature.
 *
 * Routes:
 *   GET  /pdfdraft/v1/posts-to-pdf/settings       → get settings + available templates
 *   POST /pdfdraft/v1/posts-to-pdf/settings       → save settings
 *   GET  /pdfdraft/v1/posts-to-pdf/post-data/{id} → post / user / site data for PDF generation
 */
class RestController extends WP_REST_Controller {

	/**
	 * @var string
	 */
	protected $namespace = 'pdfdraft/v1';

	/**
	 * @var string
	 */
	protected $rest_base = 'posts-to-pdf';

	/**
	 * @var PostsToPdfSettings
	 */
	private PostsToPdfSettings $settings;

	/**
	 * Constructor.
	 *
	 * @param PostsToPdfSettings $settings Settings service.
	 */
	public function __construct( PostsToPdfSettings $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Register REST routes.
	 */
	public function register_routes(): void {
		// Settings CRUD
		register_rest_route(
			$this->namespace,
			"/{$this->rest_base}/settings",
			array(
				array(
					'methods'             => \WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_settings' ),
					'permission_callback' => array( $this, 'settings_permissions' ),
				),
				array(
					'methods'             => \WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'save_settings' ),
					'permission_callback' => array( $this, 'settings_permissions' ),
				),
			)
		);

		// Published design list for the block editor sidebar (editors may not have manage_options).
		register_rest_route(
			$this->namespace,
			"/{$this->rest_base}/design-options",
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_design_options' ),
				'permission_callback' => array( $this, 'design_options_permissions' ),
			)
		);

		// Per-post data for PDF generation (public, respects post visibility)
		register_rest_route(
			$this->namespace,
			"/{$this->rest_base}/post-data/(?P<id>[\d]+)",
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_post_data' ),
				'permission_callback' => '__return_true',
				'args'                => array(
					'id' => array(
						'validate_callback' => 'rest_validate_request_arg',
						'sanitize_callback' => 'absint',
						'required'          => true,
					),
				),
			)
		);
	}

	// ── Permission callbacks ───────────────────────────────────────────────────

	/**
	 * @return bool|\WP_Error
	 */
	public function settings_permissions() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'You do not have permission to manage PDFDraft settings.', 'pdfdraft' ),
				array( 'status' => 403 )
			);
		}
		return true;
	}

	/**
	 * @return bool|\WP_Error
	 */
	public function design_options_permissions() {
		if ( ! current_user_can( 'edit_posts' ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'You do not have permission to edit content.', 'pdfdraft' ),
				array( 'status' => 403 )
			);
		}
		return true;
	}

	// ── Endpoint handlers ─────────────────────────────────────────────────────

	/**
	 * GET /pdfdraft/v1/posts-to-pdf/settings
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_settings( WP_REST_Request $request ): WP_REST_Response {
		$projects = $this->get_project_options();
		return rest_ensure_response(
			array(
				'settings'  => $this->settings->get_all(),
				'projects'  => $projects,
				'templates' => $projects,
			)
		);
	}

	/**
	 * POST /pdfdraft/v1/posts-to-pdf/settings
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|\WP_Error
	 */
	public function save_settings( WP_REST_Request $request ) {
		$body = $request->get_json_params();

		if ( ! isset( $body['settings'] ) || ! is_array( $body['settings'] ) ) {
			return new WP_Error(
				'invalid_data',
				__( 'Invalid settings payload.', 'pdfdraft' ),
				array( 'status' => 400 )
			);
		}

		$this->settings->save( $body['settings'] );

		$projects = $this->get_project_options();
		return rest_ensure_response(
			array(
				'settings'  => $this->settings->get_all(),
				'projects'  => $projects,
				'templates' => $projects,
			)
		);
	}

	/**
	 * GET /pdfdraft/v1/posts-to-pdf/design-options
	 *
	 * Lightweight list of published PDF designs for the Gutenberg "PDF Settings" panel.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_design_options( WP_REST_Request $request ): WP_REST_Response {
		$projects = $this->get_project_options();
		return rest_ensure_response(
			array(
				'projects'  => $projects,
				'templates' => $projects,
			)
		);
	}

	/**
	 * GET /pdfdraft/v1/posts-to-pdf/post-data/{id}
	 *
	 * Returns post, current user, and site data for client-side PDF generation.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|\WP_Error
	 */
	public function get_post_data( WP_REST_Request $request ) {
		$post_id = (int) $request->get_param( 'id' );
		$post    = get_post( $post_id );

		if ( ! $post ) {
			return new WP_Error(
				'post_not_found',
				__( 'Post not found.', 'pdfdraft' ),
				array( 'status' => 404 )
			);
		}

		// Visibility check: private / password-protected posts require authentication.
		if ( 'publish' !== $post->post_status ) {
			if ( ! current_user_can( 'read_post', $post_id ) ) {
				return new WP_Error(
					'rest_forbidden',
					__( 'You do not have permission to view this post.', 'pdfdraft' ),
					array( 'status' => 403 )
				);
			}
		}

		return rest_ensure_response(
			array(
				'post' => $this->get_post_fields( $post ),
				'user' => $this->get_current_user_fields(),
				'site' => $this->get_site_fields(),
			)
		);
	}

	// ── Data builders ─────────────────────────────────────────────────────────

	/**
	 * Build the post data array.
	 *
	 * @param \WP_Post $post Post object.
	 * @return array
	 */
	private function get_post_fields( \WP_Post $post ): array {
		$author     = get_userdata( $post->post_author );
		$categories = wp_get_post_terms( $post->ID, 'category', array( 'fields' => 'names' ) );
		$tags       = wp_get_post_terms( $post->ID, 'post_tag', array( 'fields' => 'names' ) );
		$thumb_id   = get_post_thumbnail_id( $post->ID );
		$thumb_url  = $thumb_id ? wp_get_attachment_image_url( $thumb_id, 'full' ) : '';

		// Raw post meta (all keys)
		$raw_meta  = get_post_meta( $post->ID );
		$meta_flat = array();
		if ( is_array( $raw_meta ) ) {
			foreach ( $raw_meta as $key => $values ) {
				// Expose only single-value, non-internal meta
				if ( 0 === strpos( $key, '_' ) ) {
					continue;
				}
				$meta_flat[ $key ] = maybe_unserialize( $values[0] ?? '' );
			}
		}

		return array(
			'title'         => html_entity_decode( get_the_title( $post ), ENT_QUOTES | ENT_HTML5 ),
			'content'       => apply_filters( 'the_content', $post->post_content ),
			'excerpt'       => has_excerpt( $post )
								? wp_strip_all_tags( apply_filters( 'the_excerpt', get_the_excerpt( $post ) ) )
								: '',
			'date'          => $post->post_date,
			'modified'      => $post->post_modified,
			'url'           => get_permalink( $post->ID ),
			'id'            => $post->ID,
			'author_name'   => $author ? $author->display_name : '',
			'author_email'  => $author ? $author->user_email : '',
			'author_url'    => $author ? $author->user_url : '',
			'featured_image' => $thumb_url ?: '',
			'categories'    => is_wp_error( $categories ) ? '' : implode( ', ', $categories ),
			'tags'          => is_wp_error( $tags ) ? '' : implode( ', ', $tags ),
			'comment_count' => (int) $post->comment_count,
			'meta'          => $meta_flat,
		);
	}

	/**
	 * Build the current user data array.  Returns null when not logged in.
	 *
	 * @return array|null
	 */
	private function get_current_user_fields(): ?array {
		$user = wp_get_current_user();

		if ( ! $user || 0 === $user->ID ) {
			return null;
		}

		$avatar_url = get_avatar_url( $user->ID, array( 'size' => 200 ) );

		return array(
			'display_name' => $user->display_name,
			'login'        => $user->user_login,
			'email'        => $user->user_email,
			'first_name'   => $user->first_name,
			'last_name'    => $user->last_name,
			'roles'        => implode( ', ', $user->roles ),
			'id'           => $user->ID,
			'url'          => $user->user_url,
			'description'  => $user->description,
			'registered'   => $user->user_registered,
			'avatar'       => $avatar_url ?: '',
		);
	}

	/**
	 * Build the site info array.
	 *
	 * @return array
	 */
	private function get_site_fields(): array {
		$logo_id  = get_theme_mod( 'custom_logo' );
		$logo_url = $logo_id ? wp_get_attachment_image_url( $logo_id, 'full' ) : '';

		return array(
			'name'         => get_bloginfo( 'name' ),
			'tagline'      => get_bloginfo( 'description' ),
			'url'          => get_bloginfo( 'url' ),
			'home_url'     => home_url(),
			'admin_email'  => get_bloginfo( 'admin_email' ),
			'logo'         => $logo_url ?: '',
			'current_date' => current_time( 'Y-m-d' ),
			'current_time' => current_time( 'H:i' ),
			'wp_version'   => get_bloginfo( 'version' ),
			'language'     => get_bloginfo( 'language' ),
		);
	}

	/**
	 * Query free templates for a specific context ('posts-to-pdf' or 'pages-to-pdf').
	 *
	 * @param string $for The pdfdraft_for meta value to filter by.
	 * @return array<array{id: int, title: string, edit_url: string}>
	 */
	private function get_template_options( string $for ): array {
		$posts = get_posts(
			array(
				'post_type'      => 'pdfdraft-design',
				'post_status'    => array( 'publish', 'draft' ),
				'posts_per_page' => 100,
				'orderby'        => 'title',
				'order'          => 'ASC',
				'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
					array(
						'key'   => 'pdfdraft_for',
						'value' => $for,
					),
				),
			)
		);

		return $this->map_to_options( $posts );
	}

	/**
	 * Query all user-created designs (projects) regardless of pdfdraft_for context.
	 *
	 * @return array<array{id: int, title: string, edit_url: string}>
	 */
	private function get_project_options(): array {
		$posts = get_posts(
			array(
				'post_type'      => 'pdfdraft-design',
				'post_status'    => 'publish',
				'posts_per_page' => 100,
				'orderby'        => 'title',
				'order'          => 'ASC',
			)
		);

		return $this->map_to_options( $posts );
	}

	/**
	 * Map WP_Post objects to option arrays.
	 *
	 * @param \WP_Post[] $posts Array of post objects.
	 * @return array<array{id: int, title: string, edit_url: string}>
	 */
	private function map_to_options( array $posts ): array {
		$options = array();
		foreach ( $posts as $post ) {
			$options[] = array(
				'id'       => $post->ID,
				'title'    => html_entity_decode( get_the_title( $post ), ENT_QUOTES | ENT_HTML5 ),
				'edit_url' => admin_url( 'post.php?post=' . $post->ID . '&action=edit' ),
			);
		}
		return $options;
	}
}
