<?php
/**
 * Answyr Desk — module wiring.
 *
 * Registers the ticket store hooks, the REST routes, the public intake form
 * shortcode, and the admin inbox screen.
 *
 * @package Answyr
 */

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

require_once __DIR__ . '/class-desk-store.php';
require_once __DIR__ . '/class-intake-fields.php';
require_once __DIR__ . '/class-suggestion-service.php';
require_once __DIR__ . '/class-desk-rest.php';

// Premium-only (@fs_premium_only) desk features — absent from the free build.
foreach ( array( 'class-macros.php', 'class-attachments.php', 'class-desk-ai.php' ) as $answyr_premium_file ) {
	$answyr_premium_path = __DIR__ . '/' . $answyr_premium_file;
	if ( is_readable( $answyr_premium_path ) ) {
		require_once $answyr_premium_path;
	}
}

final class Answyr_Desk_Module extends Answyr_Module {

	public function id(): string {
		return 'desk';
	}

	public function label(): string {
		return __( 'Desk', 'answyr' );
	}

	public function register(): void {
		( new Answyr_Desk_Rest() )->register();

		// Apply any pending DB schema upgrades (adds columns without reactivation).
		if ( is_admin() ) {
			Answyr_Desk_Store::maybe_upgrade();
		}

		// Attachments (Pro): the permission-checked download handler (logged-in only,
		// agents + ticket owners) + schema upgrade. Registered whenever the premium
		// store is present so existing links keep working regardless of plan state.
		if ( class_exists( 'Answyr_Attachments' ) ) {
			if ( is_admin() ) {
				Answyr_Attachments::maybe_upgrade();
			}
			add_action( 'admin_post_answyr_attachment', array( 'Answyr_Attachments', 'handle_download' ) );
		}

		// AI power-ups (Pro): brand voice injects into the reply + chat prompts always
		// (so the tone applies), while the triage/summary/KB routes gate on Pro below.
		if ( class_exists( 'Answyr_Desk_AI' ) ) {
			( new Answyr_Desk_AI() )->register();
		}

		add_shortcode( 'answyr_form', array( $this, 'render_form' ) );
		add_shortcode( 'answyr_portal', array( $this, 'render_portal' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'register_public_assets' ) );

		// Email on every new ticket (form intake + chat escalation both fire this).
		add_action( 'answyr_desk_ticket_created', array( $this, 'notify_new_ticket' ) );
		add_action( 'answyr_desk_customer_replied', array( $this, 'notify_customer_reply' ) );
	}

	/** Admin assets — only on the Desk inbox (now the top-level page). */
	public function enqueue_admin( string $hook ): void {
		if ( 'toplevel_page_answyr' !== $hook ) {
			return;
		}
		wp_enqueue_style( 'answyr-tokens', ANSWYR_URL . 'assets/tokens.css', array(), ANSWYR_VERSION );
		wp_enqueue_style( 'answyr-desk', ANSWYR_URL . 'assets/admin-desk.css', array( 'answyr-tokens' ), ANSWYR_VERSION );
		wp_enqueue_script( 'answyr-desk', ANSWYR_URL . 'assets/admin-desk.js', array(), ANSWYR_VERSION, true );
		wp_localize_script(
			'answyr-desk',
			'AnswyrDesk',
			array(
				'restBase' => esc_url_raw( rest_url( 'answyr/v1' ) ),
				'nonce'    => wp_create_nonce( 'wp_rest' ),
			)
		);

		// Pro: macro application (reuses the desk status/tags persistence).
		if ( answyr_is_pro() && class_exists( 'Answyr_Macros' ) ) {
			wp_enqueue_script( 'answyr-macros', ANSWYR_URL . 'assets/admin-macros.js', array( 'answyr-desk' ), ANSWYR_VERSION, true );
		}

		// Pro: attachment uploads on the ticket detail.
		if ( answyr_is_pro() && class_exists( 'Answyr_Attachments' ) ) {
			wp_enqueue_script( 'answyr-attachments', ANSWYR_URL . 'assets/admin-attachments.js', array( 'answyr-desk' ), ANSWYR_VERSION, true );
			wp_localize_script(
				'answyr-attachments',
				'AnswyrAttach',
				array(
					'restBase' => esc_url_raw( rest_url( 'answyr/v1' ) ),
					'nonce'    => wp_create_nonce( 'wp_rest' ),
					'maxBytes' => Answyr_Attachments::max_bytes(),
				)
			);
		}

		// Pro: AI triage / summary / "turn into help article".
		if ( answyr_is_pro() && class_exists( 'Answyr_Desk_AI' ) ) {
			wp_enqueue_script( 'answyr-desk-ai', ANSWYR_URL . 'assets/admin-desk-ai.js', array( 'answyr-desk' ), ANSWYR_VERSION, true );
			wp_localize_script(
				'answyr-desk-ai',
				'AnswyrDeskAI',
				array(
					'restBase' => esc_url_raw( rest_url( 'answyr/v1' ) ),
					'nonce'    => wp_create_nonce( 'wp_rest' ),
				)
			);
		}
	}

	/** Register (don't force-enqueue) public assets; the shortcodes enqueue on demand. */
	public function register_public_assets(): void {
		wp_register_style( 'answyr-tokens', ANSWYR_URL . 'assets/tokens.css', array(), ANSWYR_VERSION );
		wp_register_style( 'answyr-desk', ANSWYR_URL . 'assets/admin-desk.css', array( 'answyr-tokens' ), ANSWYR_VERSION );
		wp_register_script( 'answyr-form', ANSWYR_URL . 'assets/form.js', array(), ANSWYR_VERSION, true );
	}

	/** Customer portal — logged-in customers see and reply to their own tickets. */
	public function render_portal(): string {
		// Portal styles load for both the login form and the ticket list.
		wp_enqueue_style( 'answyr-tokens', ANSWYR_URL . 'assets/tokens.css', array(), ANSWYR_VERSION );
		wp_enqueue_style( 'answyr-portal', ANSWYR_URL . 'assets/portal.css', array( 'answyr-tokens' ), ANSWYR_VERSION );

		if ( ! is_user_logged_in() ) {
			return $this->render_login_form();
		}

		// Enqueue with full args so it loads regardless of registration timing.
		wp_enqueue_script( 'answyr-md', ANSWYR_URL . 'assets/markdown.js', array(), ANSWYR_VERSION, true );
		wp_enqueue_script( 'answyr-portal', ANSWYR_URL . 'assets/portal.js', array( 'answyr-md' ), ANSWYR_VERSION, true );
		$ss_user = wp_get_current_user();
		wp_localize_script(
			'answyr-portal',
			'AnswyrPortal',
			array(
				'restBase'     => esc_url_raw( rest_url( 'answyr/v1/desk/portal' ) ),
				'nonce'        => wp_create_nonce( 'wp_rest' ),
				'user'         => $ss_user->display_name ? $ss_user->display_name : $ss_user->user_email,
				'logoutUrl'    => esc_url_raw( wp_logout_url( get_permalink() ) ),
				'intakeFields' => Answyr_Intake_Fields::defs_for_js(),
			)
		);

		// Pro: let customers attach files to their requests.
		if ( answyr_is_pro() && class_exists( 'Answyr_Attachments' ) ) {
			wp_enqueue_script( 'answyr-portal-attachments', ANSWYR_URL . 'assets/portal-attachments.js', array( 'answyr-portal' ), ANSWYR_VERSION, true );
			wp_localize_script(
				'answyr-portal-attachments',
				'AnswyrPortalAttach',
				array(
					'restBase' => esc_url_raw( rest_url( 'answyr/v1/desk/portal' ) ),
					'nonce'    => wp_create_nonce( 'wp_rest' ),
					'maxBytes' => Answyr_Attachments::max_bytes(),
				)
			);
		}

		// Server-rendered loading state so the page is never blank if JS is slow.
		return '<div id="answyr-portal" class="answyr-portal" ' . Answyr_Settings::accent_style() . '><p class="ssp-loading">'
			. esc_html__( 'Loading your requests…', 'answyr' ) . '</p></div>';
	}

	/**
	 * Logged-out portal view: a real sign-in form. JS posts it to the portal
	 * login route so a failed attempt shows an inline error instead of bouncing
	 * to wp-login.php; with JS off, the form falls back to a normal wp-login post.
	 */
	private function render_login_form(): string {
		$redirect = get_permalink();
		$redirect = $redirect ? $redirect : home_url( '/' );

		wp_enqueue_script( 'answyr-portal-login', ANSWYR_URL . 'assets/portal-login.js', array(), ANSWYR_VERSION, true );
		wp_localize_script(
			'answyr-portal-login',
			'AnswyrPortalLogin',
			array(
				'restBase'     => esc_url_raw( rest_url( 'answyr/v1/desk/portal' ) ),
				'nonce'        => wp_create_nonce( 'answyr_portal_login' ),
				'redirect'     => $redirect,
				'signingIn'    => __( 'Signing in…', 'answyr' ),
				'genericError' => __( 'Sign-in failed. Please try again.', 'answyr' ),
			)
		);

		$form = wp_login_form(
			array(
				'echo'     => false,
				'redirect' => $redirect,
				'remember' => true,
			)
		);

		$links = '<a href="' . esc_url( wp_lostpassword_url( $redirect ) ) . '">'
			. esc_html__( 'Lost your password?', 'answyr' ) . '</a>';
		if ( get_option( 'users_can_register' ) ) {
			$links .= ' · <a href="' . esc_url( wp_registration_url() ) . '">'
				. esc_html__( 'Create an account', 'answyr' ) . '</a>';
		}

		return '<div class="answyr-portal answyr-portal-login" ' . Answyr_Settings::accent_style() . '>'
			. '<h3 class="ssp-login-title">' . esc_html__( 'Sign in to create or manage support requests', 'answyr' ) . '</h3>'
			. '<p class="ssp-login-intro">' . esc_html__( 'Sign in to create a new request or follow up on an existing one.', 'answyr' ) . '</p>'
			. '<p class="ssp-login-error" role="alert" hidden></p>'
			. $form
			. '<p class="ssp-login-links">' . $links . '</p>'
			. '</div>';
	}

	/** Minimal web-form intake. Posts to the public REST route. */
	public function render_form(): string {
		wp_enqueue_style( 'answyr-desk' );
		wp_enqueue_script( 'answyr-form' );

		$endpoint = esc_url( rest_url( 'answyr/v1/desk/tickets' ) );
		ob_start();
		?>
		<form class="answyr-form" data-endpoint="<?php echo esc_url( $endpoint ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'wp_rest' ) ); ?>" <?php echo Answyr_Settings::accent_style(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- self-escaped attribute string. ?>>
			<p><input type="text" name="name" placeholder="<?php esc_attr_e( 'Your name', 'answyr' ); ?>"></p>
			<p><input type="email" name="email" required placeholder="<?php esc_attr_e( 'Email', 'answyr' ); ?>"></p>
			<p><textarea name="message" required rows="5" placeholder="<?php esc_attr_e( 'How can we help?', 'answyr' ); ?>"></textarea></p>
			<?php
			// Admin-configured intake fields (website, versions, setup, …).
			echo Answyr_Intake_Fields::render_inputs(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- render_inputs() self-escapes via esc_attr/esc_html.
			?>
			<p><button type="submit"><?php esc_html_e( 'Send', 'answyr' ); ?></button></p>
			<p class="answyr-form-status" role="status" aria-live="polite"></p>
		</form>
		<?php
		return (string) ob_get_clean();
	}

	/**
	 * Trailing line for customer emails. We don't monitor the inbox or email
	 * replies (those never reach the ticket thread), so always steer customers to
	 * the portal — with a direct link when a Portal URL is configured.
	 */
	public static function email_footer(): string {
		$url = trim( (string) Answyr_Settings::get( 'portal_url', '' ) );
		if ( '' !== $url ) {
			/* translators: %s: portal URL */
			return "\n\n—\n" . sprintf( __( 'Please reply through your support portal — replies to this email are not monitored: %s', 'answyr' ), $url );
		}
		return "\n\n—\n" . __( 'Please reply through your support portal — replies to this email are not monitored.', 'answyr' );
	}

	/** HTML variant of email_footer() for rich (text/html) customer emails. */
	public static function email_footer_html(): string {
		$url = trim( (string) Answyr_Settings::get( 'portal_url', '' ) );
		if ( '' !== $url ) {
			return '<hr><p style="color:#666;font-size:13px">' . sprintf(
				/* translators: %s: portal URL (already an anchor). */
				esc_html__( 'Please reply through your %s — replies to this email are not monitored.', 'answyr' ),
				'<a href="' . esc_url( $url ) . '">' . esc_html__( 'support portal', 'answyr' ) . '</a>'
			) . '</p>';
		}
		return '<hr><p style="color:#666;font-size:13px">' . esc_html__( 'Please reply through your support portal — replies to this email are not monitored.', 'answyr' ) . '</p>';
	}

	/**
	 * Send an acknowledgement to the customer + a notification to the support
	 * team when a ticket is created. On Local, outgoing mail is captured by
	 * Local's Mailpit (Tools → emails) — without a mail catcher wp_mail won't
	 * actually deliver.
	 */
	public function notify_new_ticket( int $ticket_id ): void {
		if ( ! class_exists( 'Answyr_Desk_Store' ) ) {
			return;
		}
		$ticket = Answyr_Desk_Store::get_ticket( $ticket_id );
		if ( ! $ticket ) {
			return;
		}

		if ( is_email( $ticket->customer_email ) ) {
			wp_mail(
				$ticket->customer_email,
				/* translators: %d: ticket id */
				sprintf( __( 'We received your request (#%d)', 'answyr' ), $ticket_id ),
				sprintf(
					/* translators: 1: ticket id, 2: subject */
					__( "Thanks for reaching out — we've logged your request. We'll reply in your support portal and email you when there's an update.\n\nReference: #%1\$d\nSubject: %2\$s", 'answyr' ),
					$ticket_id,
					$ticket->subject
				) . self::email_footer()
			);
		}

		$notify = (string) Answyr_Settings::get( 'notify_email', get_option( 'admin_email' ) );
		if ( is_email( $notify ) ) {
			$ticket_url = admin_url( 'admin.php?page=answyr&ticket=' . $ticket_id );
			wp_mail(
				$notify,
				/* translators: %d: ticket id */
				sprintf( __( 'New Answyr ticket #%d', 'answyr' ), $ticket_id ),
				sprintf(
					/* translators: 1: ticket id, 2: customer email, 3: subject, 4: admin ticket URL */
					__( "A new support ticket has been opened in Answyr.\n\nTicket: #%1\$d\nFrom: %2\$s\nSubject: %3\$s\n\nOpen ticket #%1\$d in the Answyr Desk to reply:\n%4\$s", 'answyr' ),
					$ticket_id,
					$ticket->customer_email,
					$ticket->subject,
					$ticket_url
				)
			);
		}
	}

	/** Notify the support team when a customer replies via the portal. */
	public function notify_customer_reply( int $ticket_id ): void {
		if ( ! class_exists( 'Answyr_Desk_Store' ) ) {
			return;
		}
		$ticket = Answyr_Desk_Store::get_ticket( $ticket_id );
		if ( ! $ticket ) {
			return;
		}
		$notify = (string) Answyr_Settings::get( 'notify_email', get_option( 'admin_email' ) );
		if ( is_email( $notify ) ) {
			$ticket_url = admin_url( 'admin.php?page=answyr&ticket=' . $ticket_id );
			wp_mail(
				$notify,
				/* translators: %d: ticket id */
				sprintf( __( 'New reply on Answyr ticket #%d', 'answyr' ), $ticket_id ),
				sprintf(
					/* translators: 1: customer email, 2: ticket id, 3: subject, 4: admin ticket URL */
					__( "%1\$s replied to their support ticket in Answyr.\n\nTicket: #%2\$d\nSubject: %3\$s\n\nOpen ticket #%2\$d in the Answyr Desk to respond:\n%4\$s", 'answyr' ),
					$ticket->customer_email,
					$ticket_id,
					$ticket->subject,
					$ticket_url
				)
			);
		}
	}
}
