<?php
/**
 * REST API: /wp-json/cpecs/v1/*
 */

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

class CPECS_REST {

	const NAMESPACE_ = 'cpecs/v1';

	/** @var CPECS_DB */
	private $db;

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

	public function __construct( CPECS_DB $db, CPECS_Settings $settings ) {
		$this->db       = $db;
		$this->settings = $settings;
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
	}

	public function register_routes() {

		// --- Visitor-facing (public, no auth — protected by nonce + rate considerations) ---

		register_rest_route(
			self::NAMESPACE_,
			'/start',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'start_conversation' ),
				'permission_callback' => '__return_true',
			)
		);

		register_rest_route(
			self::NAMESPACE_,
			'/message',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'send_message' ),
				'permission_callback' => '__return_true',
			)
		);

		register_rest_route(
			self::NAMESPACE_,
			'/poll/(?P<conversation_id>\d+)',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'poll_messages' ),
				'permission_callback' => '__return_true',
			)
		);

		// --- Admin-facing (requires manage inbox capability) ---

		register_rest_route(
			self::NAMESPACE_,
			'/admin/conversations',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'admin_list_conversations' ),
				'permission_callback' => array( $this, 'admin_permission' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_,
			'/admin/conversations/(?P<id>\d+)',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'admin_get_conversation' ),
				'permission_callback' => array( $this, 'admin_permission' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_,
			'/admin/conversations/(?P<id>\d+)/reply',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'admin_reply' ),
				'permission_callback' => array( $this, 'admin_permission' ),
			)
		);

		register_rest_route(
			self::NAMESPACE_,
			'/admin/conversations/(?P<id>\d+)/close',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'admin_close' ),
				'permission_callback' => array( $this, 'admin_permission' ),
			)
		);
	}

	public function admin_permission() {
		return current_user_can( apply_filters( 'cpecs_admin_capability', 'manage_options' ) );
	}

	private function nonce_ok( WP_REST_Request $request ) {
		$nonce = $request->get_header( 'X-CPECS-Nonce' );
		return $nonce && wp_verify_nonce( $nonce, 'cpecs_widget' );
	}

	// -------------------------------------------------------------
	// Visitor endpoints
	// -------------------------------------------------------------

	public function start_conversation( WP_REST_Request $request ) {
		if ( ! $this->nonce_ok( $request ) ) {
			return new WP_Error( 'cpecs_bad_nonce', __( 'Invalid request.', 'capripio-easy-chat-support' ), array( 'status' => 403 ) );
		}

		if ( ! $this->settings->get( 'enabled' ) ) {
			return new WP_Error( 'cpecs_disabled', __( 'Chat is currently disabled.', 'capripio-easy-chat-support' ), array( 'status' => 403 ) );
		}

		$visitor_uuid = sanitize_text_field( $request->get_param( 'visitor_uuid' ) );
		if ( empty( $visitor_uuid ) ) {
			$visitor_uuid = wp_generate_uuid4();
		}

		$visitor_name  = trim( sanitize_text_field( (string) $request->get_param( 'visitor_name' ) ) );
		$visitor_email = trim( (string) $request->get_param( 'visitor_email' ) );

		if ( '' === $visitor_name ) {
			return new WP_Error( 'cpecs_missing_name', __( 'Please enter your name.', 'capripio-easy-chat-support' ), array( 'status' => 400 ) );
		}

		if ( '' !== $visitor_email && ! is_email( $visitor_email ) ) {
			return new WP_Error( 'cpecs_invalid_email', __( 'Please enter a valid email address.', 'capripio-easy-chat-support' ), array( 'status' => 400 ) );
		}

		$existing = $this->db->get_open_conversation_for_visitor( $visitor_uuid );
		if ( $existing ) {
			return rest_ensure_response(
				array(
					'conversation_id' => (int) $existing->id,
					'visitor_uuid'    => $visitor_uuid,
					'messages'        => $this->format_messages( $this->db->get_messages( $existing->id ) ),
					'online'          => $this->settings->is_within_business_hours(),
				)
			);
		}

		$conversation_id = $this->db->create_conversation(
			array(
				'visitor_uuid'  => $visitor_uuid,
				'visitor_name'  => $visitor_name,
				'visitor_email' => $visitor_email,
				'visitor_ip'    => $this->get_visitor_ip(),
				'page_url'      => $request->get_param( 'page_url' ),
				'referrer'      => $request->get_param( 'referrer' ),
				'user_agent'    => isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '',
			)
		);

		if ( ! $conversation_id ) {
			return new WP_Error( 'cpecs_db_error', __( 'Could not start the conversation. Please try again.', 'capripio-easy-chat-support' ), array( 'status' => 500 ) );
		}

		$online          = $this->settings->is_within_business_hours();
		$greeting        = $online ? $this->settings->get( 'welcome_message' ) : $this->settings->get( 'offline_message' );

		if ( $greeting ) {
			$this->db->add_message( $conversation_id, 'agent', null, $greeting );
		}

		return rest_ensure_response(
			array(
				'conversation_id' => $conversation_id,
				'visitor_uuid'    => $visitor_uuid,
				'messages'        => $this->format_messages( $this->db->get_messages( $conversation_id ) ),
				'online'          => $online,
			)
		);
	}

	public function send_message( WP_REST_Request $request ) {
		if ( ! $this->nonce_ok( $request ) ) {
			return new WP_Error( 'cpecs_bad_nonce', __( 'Invalid request.', 'capripio-easy-chat-support' ), array( 'status' => 403 ) );
		}

		$conversation_id = absint( $request->get_param( 'conversation_id' ) );
		$visitor_uuid     = sanitize_text_field( (string) $request->get_param( 'visitor_uuid' ) );
		$message          = trim( wp_strip_all_tags( (string) $request->get_param( 'message' ) ) );

		if ( ! $conversation_id || '' === $visitor_uuid || '' === $message ) {
			return new WP_Error( 'cpecs_bad_request', __( 'Missing conversation, visitor, or message.', 'capripio-easy-chat-support' ), array( 'status' => 400 ) );
		}

		$conversation = $this->db->get_conversation( $conversation_id );
		if ( ! $conversation ) {
			return new WP_Error( 'cpecs_not_found', __( 'Conversation not found.', 'capripio-easy-chat-support' ), array( 'status' => 404 ) );
		}

		// The nonce alone doesn't prove which conversation this visitor
		// owns — for logged-out visitors it's the same site-wide value
		// for everyone, refreshed only every 12 hours. Ownership is
		// actually established here, by requiring the visitor_uuid that
		// was handed back when this specific conversation was created
		// (a long random token stored in the visitor's own browser),
		// and confirming it matches this conversation's stored owner.
		if ( ! hash_equals( (string) $conversation->visitor_uuid, $visitor_uuid ) ) {
			return new WP_Error( 'cpecs_forbidden', __( 'You do not have access to this conversation.', 'capripio-easy-chat-support' ), array( 'status' => 403 ) );
		}

		$message_id = $this->db->add_message( $conversation_id, 'visitor', null, $message );

		if ( ! $message_id ) {
			return new WP_Error( 'cpecs_db_error', __( 'Could not send your message. Please try again.', 'capripio-easy-chat-support' ), array( 'status' => 500 ) );
		}

		if ( 'new' !== $conversation->status ) {
			$this->db->update_conversation_status( $conversation_id, 'open' );
		}

		if ( $this->settings->get( 'notify_on_message' ) ) {
			cpecs()->notifications->notify_new_visitor_message( $conversation_id, $message );
		}

		return rest_ensure_response(
			array(
				'message_id' => $message_id,
			)
		);
	}

	public function poll_messages( WP_REST_Request $request ) {
		if ( ! $this->nonce_ok( $request ) ) {
			return new WP_Error( 'cpecs_bad_nonce', __( 'Invalid request.', 'capripio-easy-chat-support' ), array( 'status' => 403 ) );
		}

		$conversation_id = absint( $request->get_param( 'conversation_id' ) );
		$visitor_uuid     = sanitize_text_field( (string) $request->get_param( 'visitor_uuid' ) );
		$after_id         = absint( $request->get_param( 'after' ) );

		$conversation = $this->db->get_conversation( $conversation_id );
		if ( ! $conversation ) {
			return new WP_Error( 'cpecs_not_found', __( 'Conversation not found.', 'capripio-easy-chat-support' ), array( 'status' => 404 ) );
		}

		// See send_message() for why this check matters: without it,
		// anyone can read any conversation just by guessing its ID.
		if ( '' === $visitor_uuid || ! hash_equals( (string) $conversation->visitor_uuid, $visitor_uuid ) ) {
			return new WP_Error( 'cpecs_forbidden', __( 'You do not have access to this conversation.', 'capripio-easy-chat-support' ), array( 'status' => 403 ) );
		}

		return rest_ensure_response(
			array(
				'messages' => $this->format_messages( $this->db->get_messages( $conversation_id, $after_id ) ),
				'status'   => $conversation->status,
			)
		);
	}

	// -------------------------------------------------------------
	// Admin endpoints
	// -------------------------------------------------------------

	public function admin_list_conversations( WP_REST_Request $request ) {
		$args = array(
			'status'   => sanitize_text_field( (string) $request->get_param( 'status' ) ),
			'search'   => sanitize_text_field( (string) $request->get_param( 'search' ) ),
			'page'     => max( 1, absint( $request->get_param( 'page' ) ) ),
			'per_page' => 20,
		);

		$rows = $this->db->list_conversations( $args );
		$out  = array();

		foreach ( $rows as $row ) {
			$last = $this->db->get_last_message( $row->id );
			$out[] = array(
				'id'            => (int) $row->id,
				'visitor_name'  => $row->visitor_name ?: __( 'Visitor', 'capripio-easy-chat-support' ),
				'visitor_email' => $row->visitor_email,
				'status'        => $row->status,
				'updated_at'    => $row->updated_at,
				'last_message'  => $last ? wp_trim_words( wp_strip_all_tags( $last->message ), 12 ) : '',
			);
		}

		return rest_ensure_response(
			array(
				'conversations' => $out,
				'total_open'    => $this->db->count_conversations( 'open' ),
				'total_new'     => $this->db->count_conversations( 'new' ),
			)
		);
	}

	public function admin_get_conversation( WP_REST_Request $request ) {
		$id           = absint( $request->get_param( 'id' ) );
		$conversation = $this->db->get_conversation( $id );

		if ( ! $conversation ) {
			return new WP_Error( 'cpecs_not_found', __( 'Conversation not found.', 'capripio-easy-chat-support' ), array( 'status' => 404 ) );
		}

		return rest_ensure_response(
			array(
				'id'            => (int) $conversation->id,
				'visitor_name'  => $conversation->visitor_name,
				'visitor_email' => $conversation->visitor_email,
				'page_url'      => $conversation->page_url,
				'referrer'      => $conversation->referrer,
				'status'        => $conversation->status,
				'messages'      => $this->format_messages( $this->db->get_messages( $id ) ),
			)
		);
	}

	public function admin_reply( WP_REST_Request $request ) {
		$id      = absint( $request->get_param( 'id' ) );
		$message = trim( wp_strip_all_tags( (string) $request->get_param( 'message' ) ) );

		if ( '' === $message ) {
			return new WP_Error( 'cpecs_bad_request', __( 'Message is empty.', 'capripio-easy-chat-support' ), array( 'status' => 400 ) );
		}

		$conversation = $this->db->get_conversation( $id );
		if ( ! $conversation ) {
			return new WP_Error( 'cpecs_not_found', __( 'Conversation not found.', 'capripio-easy-chat-support' ), array( 'status' => 404 ) );
		}

		$user_id    = get_current_user_id();
		$message_id = $this->db->add_message( $id, 'agent', $user_id, $message );

		if ( ! $message_id ) {
			return new WP_Error( 'cpecs_db_error', __( 'Could not send the reply. Please try again.', 'capripio-easy-chat-support' ), array( 'status' => 500 ) );
		}

		if ( 'open' !== $conversation->status ) {
			$this->db->update_conversation_status( $id, 'open' );
		}

		return rest_ensure_response( array( 'message_id' => $message_id ) );
	}

	public function admin_close( WP_REST_Request $request ) {
		$id = absint( $request->get_param( 'id' ) );

		$conversation = $this->db->get_conversation( $id );
		if ( ! $conversation ) {
			return new WP_Error( 'cpecs_not_found', __( 'Conversation not found.', 'capripio-easy-chat-support' ), array( 'status' => 404 ) );
		}

		$this->db->update_conversation_status( $id, 'closed' );

		return rest_ensure_response( array( 'status' => 'closed' ) );
	}

	// -------------------------------------------------------------
	// Helpers
	// -------------------------------------------------------------

	private function format_messages( $rows ) {
		$out = array();
		foreach ( $rows as $row ) {
			$out[] = array(
				'id'          => (int) $row->id,
				'sender_type' => $row->sender_type,
				'message'     => $row->message,
				'created_at'  => $row->created_at,
			);
		}
		return $out;
	}

	private function get_visitor_ip() {
		if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
			$parts = explode( ',', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) );
			return trim( $parts[0] );
		}
		if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
			return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
		}
		return '';
	}
}
