<?php
/**
 * Chat CSAT model.
 *
 * @package KimaAI\Models
 */

declare(strict_types=1);

namespace KimaAI\Models;

defined('ABSPATH') || exit;

class ChatCsatModel {
  use HasSchema;

  public const TABLE = 'kimaai_chat_csat';
  public const PRIMARY_KEY = 'id';

  public const COLUMNS = [
    'id' => 'BIGINT(20) NOT NULL AUTO_INCREMENT',
    'user_id' => 'BIGINT(20) NOT NULL',
    'ip' => 'VARCHAR(64) NOT NULL',
    'session_id' => 'VARCHAR(64) NOT NULL',
    'rating' => 'TINYINT NOT NULL', // 1..5
    'comment' => 'TEXT NULL',
    'created_at' => 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP',
  ];

  public const INDEXES = [
    'UNIQUE KEY uniq_session (session_id)',
  ];

  /**
   * The fully-qualified table name.
   *
   * @var string
   */
  private string $table_name;

  /**
   * ChatCsatModel constructor.
   */
  public function __construct() {
    global $wpdb;
    $this->table_name = esc_sql($wpdb->prefix . self::TABLE);
  }

  /**
   * Inserts a new CSAT rating and returns the new row ID.
   *
   * @param array $data Rating data.
   * @return int The inserted row ID, or 0 on failure.
   */
  public function insert(array $data): int {
    global $wpdb;

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
    $result = $wpdb->insert(
      $this->table_name,
      [
        'user_id' => (int) ($data['user_id'] ?? 0),
        'ip' => (string) ($data['ip'] ?? ''),
        'session_id' => (string) ($data['session_id'] ?? ''),
        'rating' => (int) ($data['rating'] ?? 0),
        'comment' => $data['comment'] ?? null,
        'created_at' => current_time('mysql'),
      ],
      ['%d', '%s', '%s', '%d', '%s', '%s']
    );

    return $result ? (int) $wpdb->insert_id : 0;
  }

  /**
   * Returns true if a CSAT rating already exists for the given session.
   *
   * @param string $session_id The session ID.
   * @return bool
   */
  public function existsForSession(string $session_id): bool {
    global $wpdb;

    $session_id = sanitize_text_field($session_id);
    if ($session_id === '') {
      return false;
    }

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
    $val = $wpdb->get_var(
      $wpdb->prepare(
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        "SELECT 1 FROM {$this->table_name} WHERE session_id = %s LIMIT 1",
        $session_id
      )
    );

    return (bool) $val;
  }

  /**
   * Deletes CSAT rows by primary key IDs and returns the number of deleted rows.
   *
   * @param array $ids Row IDs to delete.
   * @return int
   */
  public function deleteByIds(array $ids): int {
    global $wpdb;

    $ids = array_values(array_filter(array_map('absint', $ids)));
    if ($ids === []) {
      return 0;
    }

    $placeholders = implode(', ', array_fill(0, count($ids), '%d'));

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
    $result = $wpdb->query(
      $wpdb->prepare(
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
        "DELETE FROM {$this->table_name} WHERE id IN ($placeholders)",
        ...$ids
      )
    );

    return is_numeric($result) ? (int) $result : 0;
  }

  /**
   * Returns CSAT row IDs matching the given session IDs.
   *
   * @param array $session_ids Session IDs to look up.
   * @return int[]
   */
  public function getIdsBySessionIds(array $session_ids): array {
    global $wpdb;

    $session_ids = array_values(array_filter(array_map('sanitize_text_field', $session_ids)));
    if ($session_ids === []) {
      return [];
    }

    $placeholders = implode(', ', array_fill(0, count($session_ids), '%s'));

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
    $rows = $wpdb->get_col(
      $wpdb->prepare(
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
        "SELECT id FROM {$this->table_name} WHERE session_id IN ($placeholders)",
        ...$session_ids
      )
    );

    return array_values(array_unique(array_map('intval', $rows)));
  }

  /**
   * Deletes CSAT rows for the given session IDs and returns the number of deleted rows.
   *
   * @param array $session_ids Session IDs whose rows should be deleted.
   * @return int
   */
  public function deleteBySessionIds(array $session_ids): int {
    global $wpdb;

    $session_ids = array_values(array_filter(array_map('sanitize_text_field', $session_ids)));
    if ($session_ids === []) {
      return 0;
    }

    $placeholders = implode(', ', array_fill(0, count($session_ids), '%s'));

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
    $result = $wpdb->query(
      $wpdb->prepare(
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
        "DELETE FROM {$this->table_name} WHERE session_id IN ($placeholders)",
        ...$session_ids
      )
    );

    return is_numeric($result) ? (int) $result : 0;
  }
}
