<?php
/**
 * Chatbot feedback REST routes.
 *
 * @package KimaAI\ChatBot
 */

declare(strict_types=1);

namespace KimaAI\ChatBot;

use KimaAI\Ai\Security;
use KimaAI\Models\ChatCsatModel;
use KimaAI\Models\ChatFeedbackModel;
use WP_REST_Request;
use WP_REST_Response;

defined('ABSPATH') || exit;

class ChatbotFeedback {

  /**
   * Create the feedback handler.
   *
   * @param ChatCsatModel $csat_model CSAT data model.
   * @param ChatFeedbackModel $feedback_model Message feedback data model.
   * @param Security $security Security helper.
   */
  public function __construct(private ChatCsatModel $csat_model, private ChatFeedbackModel $feedback_model, private Security $security) {
  }

  /**
   * Register feedback REST API routes.
   *
   * @return void
   */
  public function registerRoutes(): void {
    register_rest_route(
      'kimaai/v1',
      '/chatbot/feedback/message',
      [
        'methods' => 'POST',
        'callback' => [$this, 'saveMessageFeedback'],
        'permission_callback' => '__return_true',
        'args' => [
          'session_id' => [
            'required' => true,
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitizeIdentifier'],
            'validate_callback' => [$this, 'validateIdentifier'],
          ],
          'message_id' => [
            'required' => true,
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitizeIdentifier'],
            'validate_callback' => [$this, 'validateIdentifier'],
          ],
          'rating' => [
            'required' => true,
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitizeMessageRating'],
            'validate_callback' => [$this, 'validateMessageRating'],
          ],
          'comment' => [
            'required' => false,
            'type' => 'string',
            'default' => '',
            'sanitize_callback' => [$this, 'sanitizePlainTextarea'],
          ],
        ],
      ]
    );

    register_rest_route(
      'kimaai/v1',
      '/chatbot/feedback/csat',
      [
        'methods' => 'POST',
        'callback' => [$this, 'saveCsatFeedback'],
        'permission_callback' => '__return_true',
        'args' => [
          'session_id' => [
            'required' => true,
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitizeIdentifier'],
            'validate_callback' => [$this, 'validateIdentifier'],
          ],
          'rating' => [
            'required' => true,
            'type' => 'integer',
            'sanitize_callback' => 'absint',
            'validate_callback' => [$this, 'validateCsatRating'],
          ],
          'comment' => [
            'required' => false,
            'type' => 'string',
            'default' => '',
            'sanitize_callback' => [$this, 'sanitizePlainTextarea'],
          ],
        ],
      ]
    );

    register_rest_route(
      'kimaai/v1',
      '/chatbot/feedback/message/delete',
      [
        'methods' => 'POST',
        'callback' => [$this, 'deleteMessageFeedback'],
        'permission_callback' => [$this, 'canManageFeedback'],
        'args' => [
          'ids' => [
            'required' => true,
            'type' => 'array',
          ],
        ],
      ]
    );

    register_rest_route(
      'kimaai/v1',
      '/chatbot/feedback/csat/delete',
      [
        'methods' => 'POST',
        'callback' => [$this, 'deleteCsatFeedback'],
        'permission_callback' => [$this, 'canManageFeedback'],
        'args' => [
          'ids' => [
            'required' => true,
            'type' => 'array',
          ],
        ],
      ]
    );
  }

  /**
   * Save a thumbs-up or thumbs-down message feedback entry.
   *
   * @param WP_REST_Request $request REST request.
   * @return WP_REST_Response
   */
  public function saveMessageFeedback(WP_REST_Request $request): WP_REST_Response {
    $session_id = (string) $request->get_param('session_id');
    $message_id = (string) $request->get_param('message_id');
    $rating = (int) $request->get_param('rating');
    $comment = (string) $request->get_param('comment');

    if ($session_id === '' || $message_id === '' || !in_array($rating, [1, -1], true)) {
      return new WP_REST_Response(['error' => __('Invalid feedback payload.', 'kimaai')], 400);
    }

    // Only accept comment on thumbs-down
    $comment = ($rating === -1) ? $comment : '';

    $user_id = (int) get_current_user_id();
    $ip = $this->security->getIpAddress();

    $insert_id = $this->feedback_model->insert([
      'user_id' => $user_id,
      'ip' => $ip,
      'session_id' => $session_id,
      'message_id' => $message_id,
      'rating' => $rating,
      'comment' => $comment,
    ]);

    return new WP_REST_Response([
      'ok' => true,
      'id' => $insert_id,
    ], 200);
  }

  /**
   * Save a CSAT (1–5 star) feedback entry.
   *
   * @param WP_REST_Request $request REST request.
   * @return WP_REST_Response
   */
  public function saveCsatFeedback(WP_REST_Request $request): WP_REST_Response {
    $session_id = (string) $request->get_param('session_id');
    $rating = (int) $request->get_param('rating');
    $comment = (string) $request->get_param('comment');

    if ($session_id === '' || $rating < 1 || $rating > 5) {
      return new WP_REST_Response(['error' => __('Invalid CSAT payload.', 'kimaai')], 400);
    }

    $user_id = (int) get_current_user_id();
    $ip = $this->security->getIpAddress();

    $insert_id = $this->csat_model->insert([
      'user_id' => $user_id,
      'ip' => $ip,
      'session_id' => $session_id,
      'rating' => $rating,
      'comment' => $comment,
    ]);

    return new WP_REST_Response([
      'ok' => true,
      'id' => $insert_id,
    ], 200);
  }

  /**
   * Delete one or more message feedback entries by ID.
   *
   * @param WP_REST_Request $request REST request.
   * @return WP_REST_Response
   */
  public function deleteMessageFeedback(WP_REST_Request $request): WP_REST_Response {
    $ids = $this->sanitizeIdList($request->get_param('ids'));

    if ($ids === []) {
      return new WP_REST_Response(['error' => __('No valid feedback IDs provided.', 'kimaai')], 400);
    }

    $deleted = $this->feedback_model->deleteByIds($ids);

    return new WP_REST_Response([
      'ok' => true,
      'deleted' => $deleted,
      'ids' => $ids,
    ], 200);
  }

  /**
   * Delete one or more CSAT feedback entries by ID.
   *
   * @param WP_REST_Request $request REST request.
   * @return WP_REST_Response
   */
  public function deleteCsatFeedback(WP_REST_Request $request): WP_REST_Response {
    $ids = $this->sanitizeIdList($request->get_param('ids'));

    if ($ids === []) {
      return new WP_REST_Response(['error' => __('No valid CSAT IDs provided.', 'kimaai')], 400);
    }

    $deleted = $this->csat_model->deleteByIds($ids);

    return new WP_REST_Response([
      'ok' => true,
      'deleted' => $deleted,
      'ids' => $ids,
    ], 200);
  }

  /**
   * Check whether the current user can manage feedback entries.
   *
   * @return bool
   */
  public function canManageFeedback(): bool {
    return current_user_can('manage_options');
  }

  /**
   * Sanitize and deduplicate an array of positive integer IDs.
   *
   * @param mixed $value Raw input value.
   * @return int[]
   */
  private function sanitizeIdList(mixed $value): array {
    if (!is_array($value)) {
      return [];
    }

    $ids = array_map('absint', $value);
    $ids = array_filter($ids, static fn (int $id): bool => $id > 0);

    return array_values(array_unique($ids));
  }

  /**
   * Sanitize a plain-text textarea value, stripping HTML and truncating.
   *
   * @param mixed $value Raw input value.
   * @return string
   */
  public function sanitizePlainTextarea(mixed $value): string {
    $value = is_scalar($value) ? (string) $value : '';
    $value = wp_unslash($value);
    $value = sanitize_textarea_field($value);

    return mb_substr($value, 0, 1000);
  }

  /**
   * Sanitize an identifier string, keeping only alphanumeric, colon, dash, and underscore.
   *
   * @param mixed $value Raw input value.
   * @return string
   */
  public function sanitizeIdentifier(mixed $value): string {
    $value = is_scalar($value) ? (string) $value : '';
    $value = wp_unslash($value);
    $value = preg_replace('/[^A-Za-z0-9:_-]/', '', $value) ?? '';

    return substr($value, 0, 191);
  }

  /**
   * Validate that a value is a non-empty, safe identifier string.
   *
   * @param mixed $value Raw input value.
   * @return bool
   */
  public function validateIdentifier(mixed $value): bool {
    if (!is_scalar($value)) {
      return false;
    }

    $value = (string) $value;

    return $value !== '' && strlen($value) <= 191 && preg_match('/^[A-Za-z0-9:_-]+$/', $value) === 1;
  }

  /**
   * Validate that a message rating is +1 or -1.
   *
   * @param mixed $value Raw input value.
   * @return bool
   */
  public function validateMessageRating(mixed $value): bool {
    return in_array((int) $value, [1, -1], true);
  }

  /**
   * Validate that a CSAT rating is between 1 and 5.
   *
   * @param mixed $value Raw input value.
   * @return bool
   */
  public function validateCsatRating(mixed $value): bool {
    $rating = (int) $value;
    return $rating >= 1 && $rating <= 5;
  }

  /**
   * Sanitize a message rating to an integer.
   *
   * @param mixed $value Raw input value.
   * @return int
   */
  public function sanitizeMessageRating(mixed $value): int {
    return (int) $value;
  }
}
