<?php
/**
 * Booking Notes Handler
 *
 * Manages internal notes, system logs, email/SMS references
 * attached to bookings.
 *
 * @package WahraRentalsBookings
 */

defined('ABSPATH') || exit;

/**
 * Booking notes class
 */
class WAHRB_Booking_Notes {

    /**
     * Single instance
     *
     * @var WAHRB_Booking_Notes|null
     */
    private static ?WAHRB_Booking_Notes $instance = null;

    /**
     * Database helper
     *
     * @var WAHRB_Database
     */
    private WAHRB_Database $db;

    /**
     * Get single instance
     *
     * @return WAHRB_Booking_Notes
     */
    public static function instance(): WAHRB_Booking_Notes {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor
     */
    private function __construct() {
        $this->db = WAHRB_Database::instance();
    }

    /**
     * Add a note to a booking
     *
     * @param int    $booking_id Booking ID.
     * @param string $content    Note content.
     * @param string $note_type  One of: manual, system, email, sms.
     * @param bool   $is_private Whether the note is private (admin/vendor only).
     * @param int|null $author_id  User ID of the author (null for system notes).
     * @return int|false Inserted note_id or false on failure.
     */
    public function add(int $booking_id, string $content, string $note_type = 'manual', bool $is_private = false, ?int $author_id = null): int|false {
        global $wpdb;

        if (empty($content)) {
            return false;
        }

        if (is_null($author_id)) {
            $author_id = get_current_user_id() ?: null;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $inserted = $wpdb->insert(
            $this->db->table('booking_notes'),
            [
                'booking_id' => $booking_id,
                'author_id'  => $author_id,
                'content'    => $content,
                'is_private' => $is_private ? 1 : 0,
                'note_type'  => $note_type,
            ],
            ['%d', '%d', '%s', '%d', '%s']
        );

        if (!$inserted) {
            return false;
        }

        $note_id = (int) $wpdb->insert_id;

        /**
         * Fires after a booking note is added.
         *
         * @param int    $note_id    Note ID.
         * @param int    $booking_id Booking ID.
         * @param string $note_type  Note type.
         */
        do_action('wahrb_booking_note_added', $note_id, $booking_id, $note_type);

        return $note_id;
    }

    /**
     * Add a system note (auto-generated by the plugin)
     *
     * @param int    $booking_id Booking ID.
     * @param string $content    Note content.
     * @return int|false
     */
    public function add_system_note(int $booking_id, string $content): int|false {
        return $this->add($booking_id, $content, 'system', false, null);
    }

    /**
     * Get all notes for a booking
     *
     * @param int    $booking_id    Booking ID.
     * @param string $type_filter   Optional type filter (manual, system, email, sms, or empty for all).
     * @param bool   $include_private Whether to include private notes.
     * @return array
     */
    public function get_notes(int $booking_id, string $type_filter = '', bool $include_private = true): array {
        global $wpdb;

        $where = ['bn.booking_id = %d'];
        $params = [$booking_id];

        if ($type_filter) {
            $where[] = 'bn.note_type = %s';
            $params[] = $type_filter;
        }

        if (!$include_private) {
            $where[] = 'bn.is_private = 0';
        }

        $where_sql = implode(' AND ', $where);

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $notes = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT bn.*, u.display_name as author_name FROM {$this->db->table('booking_notes')} bn LEFT JOIN {$wpdb->users} u ON bn.author_id = u.ID WHERE {$where_sql} ORDER BY bn.created_at DESC",
                ...$params
            ),
            ARRAY_A
        );

        return $notes ?: [];
    }

    /**
     * Get a single note
     *
     * @param int $note_id Note ID.
     * @return array|null
     */
    public function get_note(int $note_id): ?array {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $note = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT bn.*, u.display_name as author_name FROM {$this->db->table('booking_notes')} bn LEFT JOIN {$wpdb->users} u ON bn.author_id = u.ID WHERE bn.note_id = %d",
                $note_id
            ),
            ARRAY_A
        );

        return $note ?: null;
    }

    /**
     * Delete a note
     *
     * @param int $note_id    Note ID.
     * @param int $booking_id Booking ID (for ownership check).
     * @return bool
     */
    public function delete(int $note_id, int $booking_id): bool {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $deleted = $wpdb->delete(
            $this->db->table('booking_notes'),
            [
                'note_id'    => $note_id,
                'booking_id' => $booking_id,
            ],
            ['%d', '%d']
        );

        return (bool) $deleted;
    }

    /**
     * Count notes for a booking
     *
     * @param int $booking_id Booking ID.
     * @return int
     */
    public function count(int $booking_id): int {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        return (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->db->table('booking_notes')} WHERE booking_id = %d",
                $booking_id
            )
        );
    }
}
