<?php
/**
 * Central REST router for admin-authenticated endpoints + public coupon tracking.
 *
 * @package SuiteMkt3k
 */

namespace SuiteMkt3k\Rest;

use SuiteMkt3k\Modules\Coupons\Coupon_Manager;
use SuiteMkt3k\Modules\Newsletter\Newsletter_Manager;
use SuiteMkt3k\Modules\Subscribers\Subscriber_Manager;
use SuiteMkt3k\Modules\Statistics\Stats_Collector;
use SuiteMkt3k\Security\Capabilities;
use SuiteMkt3k\Security\Rate_Limiter;
use SuiteMkt3k\Utils\Sanitizer;
use SuiteMkt3k\Utils\Validator;

defined( 'ABSPATH' ) || exit;

final class Rest_Router {

	public static function register(): void {
		add_action( 'rest_api_init', array( __CLASS__, 'register_routes' ) );
	}

	public static function register_routes(): void {
		// Admin: coupon CRUD via REST (used by the React designer).
		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/coupons',
			array(
				array(
					'methods'             => 'GET',
					'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
					'callback'            => static fn() => rest_ensure_response( Coupon_Manager::list( 200 ) ),
				),
				array(
					'methods'             => 'POST',
					'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
					'callback'            => static function ( \WP_REST_Request $r ) {
						$payload = (array) $r->get_json_params();
						$id      = (int) ( $payload['id'] ?? 0 );
						return rest_ensure_response( Coupon_Manager::save( $payload, $id ) );
					},
				),
			)
		);

		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/coupons/(?P<id>\d+)',
			array(
				'methods'             => 'GET',
				'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
				'callback'            => static function ( \WP_REST_Request $r ) {
					$row = Coupon_Manager::get( (int) $r['id'] );
					return $row ? rest_ensure_response( $row ) : new \WP_Error( 'not_found', __( 'Not found', 'suitemkt3k' ), array( 'status' => 404 ) );
				},
			)
		);

		// Newsletter
		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/newsletters',
			array(
				array(
					'methods'             => 'GET',
					'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
					'callback'            => static fn() => rest_ensure_response( Newsletter_Manager::list( 200 ) ),
				),
				array(
					'methods'             => 'POST',
					'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
					'callback'            => static function ( \WP_REST_Request $r ) {
						$payload = (array) $r->get_json_params();
						$id      = (int) ( $payload['id'] ?? 0 );
						return rest_ensure_response( Newsletter_Manager::save( $payload, $id ) );
					},
				),
			)
		);

		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/newsletters/(?P<id>\d+)',
			array(
				'methods'             => 'GET',
				'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
				'callback'            => static function ( \WP_REST_Request $r ) {
					$row = Newsletter_Manager::get( (int) $r['id'] );
					return $row ? rest_ensure_response( $row ) : new \WP_Error( 'not_found', __( 'Not found', 'suitemkt3k' ), array( 'status' => 404 ) );
				},
			)
		);

		// Coupon impression / click beacon
		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/public/coupon/track',
			array(
				'methods'             => 'POST',
				'permission_callback' => '__return_true',
				'callback'            => array( __CLASS__, 'track_coupon' ),
			)
		);

		// Coupon optin (popup step 2)
		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/public/coupon/optin',
			array(
				'methods'             => 'POST',
				'permission_callback' => '__return_true',
				'callback'            => array( __CLASS__, 'coupon_optin' ),
			)
		);

		// Blog posts for newsletter import.
		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/posts',
			array(
				'methods'             => 'GET',
				'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
				'callback'            => array( __CLASS__, 'list_posts' ),
			)
		);

		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/posts/(?P<id>\d+)',
			array(
				'methods'             => 'GET',
				'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
				'callback'            => array( __CLASS__, 'get_post_for_import' ),
			)
		);

		// Test email (settings / newsletter / cart): each module registers its own admin_post hooks too;
		// here we expose a unified REST for live preview testing.
		register_rest_route(
			SUITEMKT3K_REST_NAMESPACE,
			'/test-email',
			array(
				'methods'             => 'POST',
				'permission_callback' => static fn() => current_user_can( Capabilities::EDIT_CAMPAIGN ),
				'callback'            => array( __CLASS__, 'unified_test_email' ),
			)
		);
	}

	/**
	 * Import payload for a published blog post (newsletter designer).
	 *
	 * @return array<string, mixed>|null
	 */
	public static function post_import_payload( \WP_Post $post ): ?array {
		if ( 'post' !== $post->post_type || 'publish' !== $post->post_status ) {
			return null;
		}
		$thumb_id  = (int) get_post_thumbnail_id( $post );
		$image_url = $thumb_id ? (string) ( wp_get_attachment_image_url( $thumb_id, 'large' ) ?: '' ) : '';
		$excerpt   = has_excerpt( $post ) ? get_the_excerpt( $post ) : wp_trim_words( wp_strip_all_tags( $post->post_content ), 55, '…' );
		$title     = get_the_title( $post );
		return array(
			'id'        => (int) $post->ID,
			'title'     => $title,
			'subject'   => $title,
			'excerpt'   => $excerpt,
			'image_id'  => $thumb_id,
			'image_url' => $image_url,
			'link'      => (string) get_permalink( $post ),
		);
	}

	/**
	 * Published blog posts for the newsletter designer import dropdown.
	 *
	 * @return list<array{id: int, title: string, import: array<string, mixed>}>
	 */
	public static function published_posts_import_list( int $per_page = 30 ): array {
		$per_page = min( 50, max( 1, $per_page ) );
		$query    = new \WP_Query(
			array(
				'post_type'              => 'post',
				'post_status'            => 'publish',
				'posts_per_page'         => $per_page,
				'orderby'                => 'date',
				'order'                  => 'DESC',
				'no_found_rows'          => true,
				'update_post_meta_cache' => false,
				'update_post_term_cache' => false,
			)
		);
		$posts = array();
		foreach ( $query->posts as $post ) {
			if ( ! $post instanceof \WP_Post ) {
				continue;
			}
			$import = self::post_import_payload( $post );
			if ( null === $import ) {
				continue;
			}
			$posts[] = array(
				'id'     => (int) $post->ID,
				'title'  => get_the_title( $post ),
				'import' => $import,
			);
		}
		return $posts;
	}

	/**
	 * @return list<array{id: int, title: string}>
	 */
	public static function published_posts_list( int $per_page = 30 ): array {
		$out = array();
		foreach ( self::published_posts_import_list( $per_page ) as $row ) {
			$out[] = array(
				'id'    => (int) $row['id'],
				'title' => (string) $row['title'],
			);
		}
		return $out;
	}

	public static function list_posts( \WP_REST_Request $request ): \WP_REST_Response {
		$per_page = min( 50, max( 1, (int) $request->get_param( 'per_page' ) ?: 30 ) );
		return new \WP_REST_Response(
			array( 'posts' => self::published_posts_import_list( $per_page ) ),
			200
		);
	}

	public static function get_post_for_import( \WP_REST_Request $request ): \WP_REST_Response {
		$post = get_post( (int) $request['id'] );
		$payload = ( $post instanceof \WP_Post ) ? self::post_import_payload( $post ) : null;
		if ( null === $payload ) {
			return new \WP_REST_Response( array( 'ok' => false ), 404 );
		}
		return new \WP_REST_Response( $payload, 200 );
	}

	public static function track_coupon( \WP_REST_Request $request ): \WP_REST_Response {
		$visitor = Rate_Limiter::visitor_id();
		if ( ! Rate_Limiter::check( 'coupon_beacon', $visitor, 60, 60 ) ) {
			return new \WP_REST_Response( array( 'ok' => false ), 429 );
		}
		$params    = (array) $request->get_json_params();
		$coupon_id = (int) ( $request->get_param( 'coupon_id' ) ?? ( $params['coupon_id'] ?? 0 ) );
		$type      = sanitize_key( (string) ( $request->get_param( 'type' ) ?? ( $params['type'] ?? '' ) ) );
		if ( ! Validator::is_in( $type, array( 'impression', 'click', 'conversion' ) ) ) {
			return new \WP_REST_Response( array( 'ok' => false ), 400 );
		}
		Stats_Collector::record(
			array(
				'event_type'   => $type,
				'entity_type'  => 'coupon',
				'entity_id'    => $coupon_id,
				'visitor_hash' => $visitor,
			)
		);
		return new \WP_REST_Response( array( 'ok' => true ), 200 );
	}

	public static function coupon_optin( \WP_REST_Request $request ): \WP_REST_Response {
		\SuiteMkt3k\Utils\I18n::ensure_textdomain();
		$visitor = Rate_Limiter::visitor_id();
		if ( ! Rate_Limiter::check( 'coupon_optin', $visitor, 5, 60 ) ) {
			return new \WP_REST_Response( array( 'ok' => false, 'message' => __( 'Too many attempts.', 'suitemkt3k' ) ), 429 );
		}
		$nonce = (string) $request->get_param( '_wpnonce' );
		if ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
			return new \WP_REST_Response( array( 'ok' => false, 'message' => __( 'Security check failed.', 'suitemkt3k' ) ), 403 );
		}
		$coupon_id = (int) $request->get_param( 'coupon_id' );
		$email     = Sanitizer::email( $request->get_param( 'email' ) ?? '' );
		if ( ! Validator::is_valid_email( $email ) ) {
			return new \WP_REST_Response( array( 'ok' => false, 'message' => __( 'Valid email required.', 'suitemkt3k' ) ), 400 );
		}
		$consent = filter_var( $request->get_param( 'consent' ), FILTER_VALIDATE_BOOLEAN );
		if ( ! $consent ) {
			return new \WP_REST_Response( array( 'ok' => false, 'message' => __( 'Please accept the privacy policy.', 'suitemkt3k' ) ), 400 );
		}
		$coupon = Coupon_Manager::get( $coupon_id );
		if ( ! $coupon || Coupon_Manager::STATUS_ACTIVE !== (string) ( $coupon['status'] ?? '' ) ) {
			return new \WP_REST_Response( array( 'ok' => false, 'message' => __( 'This coupon is not available.', 'suitemkt3k' ) ), 404 );
		}
		$subscriber = Subscriber_Manager::upsert(
			array(
				'name'                 => $request->get_param( 'name' ) ?? '',
				'email'                => $email,
				'birth_date'           => $request->get_param( 'birth_date' ) ?? '',
				'source_type'          => 'coupon_popup',
				'source_campaign_id'   => $coupon_id,
				'source_campaign_name' => (string) $coupon['name'],
				'ip'                   => \SuiteMkt3k\Utils\Sanitizer::server( 'REMOTE_ADDR', 'text' ),
				'locale'               => get_locale(),
			)
		);

		if ( $subscriber ) {
			\SuiteMkt3k\Utils\I18n::ensure_textdomain();

			$html = \SuiteMkt3k\Modules\Coupons\Coupon_Email_Template_Manager::render_html( $coupon, $subscriber );
			$tpl  = \SuiteMkt3k\Modules\Coupons\Coupon_Email_Template_Manager::get_template();
			$mailer = new \SuiteMkt3k\Email\Mailer();
			$mailer->send(
				array(
					'to'        => $email,
					'subject'   => (string) ( $tpl['subject'] ?? \SuiteMkt3k\Modules\Coupons\Coupon_Email_Template_Manager::default_subject() ),
					'html'      => $html,
					'context'   => 'coupon_optin',
					'entity_id' => $coupon_id,
				)
			);
			Stats_Collector::record(
				array(
					'event_type'   => 'conversion',
					'entity_type'  => 'coupon',
					'entity_id'    => $coupon_id,
					'subscriber_id'=> (int) $subscriber['id'],
				)
			);
		}
		return new \WP_REST_Response( array( 'ok' => true, 'message' => __( 'Thanks! Check your inbox for your coupon.', 'suitemkt3k' ) ), 200 );
	}

	public static function unified_test_email( \WP_REST_Request $request ): \WP_REST_Response {
		$to     = Sanitizer::email( $request->get_param( 'to' ) ?? '' );
		$kind   = sanitize_key( (string) $request->get_param( 'kind' ) );
		if ( '' === $to ) {
			return new \WP_REST_Response( array( 'ok' => false, 'message' => __( 'Invalid email.', 'suitemkt3k' ) ), 400 );
		}
		$mailer = new \SuiteMkt3k\Email\Mailer();
		$ok = $mailer->send_test( $to );
		return new \WP_REST_Response( array( 'ok' => $ok ), $ok ? 200 : 500 );
	}
}
