<?php

namespace SGC\eGiftCard\Http\Model;

use wpdb;
defined( 'ABSPATH' ) || exit; // Prevent direct file access.
/**
 * Class Model
 *
 * Base model class for interacting with the database using WordPress's wpdb class.
 */
class Model {
    
    /**
     * @var wpdb The WordPress database abstraction object.
     */
    protected $_wpdb;

    /**
     * @var string The name of the database table.
     */
    protected $tableName;

    /**
     * @var array Singleton instances of models.
     */
    private static $instances = [];

    /**
     * Model constructor.
     *
     * Initializes the database connection and sets the table name.
     */
    public function __construct() {
        global $wpdb;
        $this->_wpdb = $wpdb;
        $this->tableName = $this->_wpdb->prefix . $this->tableName;
    }

    /**
     * Get the singleton instance of the model.
     *
     * @return static The singleton instance.
     */
    public static function getInstance() {
        $cls = static::class;
        if (!isset(static::$instances[$cls])) {
            static::$instances[$cls] = new static();
        }

        return static::$instances[$cls];
    }

    /**
     * Get the name of the database table.
     *
     * @return string The name of the table.
     */
    public function getTableName() {
        return $this->tableName;
    }

    /**
     * Find a record by ID.
     *
     * @param int $id The ID of the record to find.
     * @return object|null The record, or null if not found.
     */
    public static function find( $id ) {
        $model = static::getInstance();
        return $model->_wpdb->get_row( $model->_wpdb->prepare( "SELECT * FROM {$model->tableName} WHERE id = %d", $id ) );
    }

    /**
     * Store a new record in the database.
     *
     * @param array $data The data to insert.
     * @return int|false The ID of the inserted record, or false on failure.
     */
    public function store( $data ) {
        $model = static::getInstance();

        // Insert data into the table
        $inserted = $model->_wpdb->insert( $model->tableName, $data );

        // Check if the insertion was successful
        return $inserted ? $model->_wpdb->insert_id : false;
    }

    /**
     * Update an existing record in the database.
     *
     * @param array $data The data to update.
     * @param int $id The ID of the record to update.
     * @return int|false The number of rows updated, or false on failure.
     */
    public function update( $data, $id ) {
        $model = static::getInstance();
        return $model->_wpdb->update( $model->tableName, $data, [ 'id' => $id ] );
    }

    /**
     * Delete a record from the database.
     *
     * @param int $id The ID of the record to delete.
     * @return int|false The number of rows deleted, or false on failure.
     */
    public function destroy( $id ) {
        $model = static::getInstance();
        return $model->_wpdb->delete( $model->tableName, [ 'id' => $id ] );
    }

    /**
     * Retrieve records from the table.
     *
     * @param int|null $limit The number of records to retrieve. If null, retrieves all records.
     * @param int $offset The offset for pagination.
     * @return array An array of records.
     */
    public static function all( $limit = null, $offset = 0 )
    {
        $model = static::getInstance();

         // Base query
        $query = "SELECT * FROM {$model->tableName} ORDER BY ID DESC";

        // Add LIMIT and OFFSET if $limit is not null
        if ( ! is_null( $limit ) ) {
            $query .= $model->_wpdb->prepare( " LIMIT %d OFFSET %d", $limit, $offset );
        }

        return $model->_wpdb->get_results( $query );
    }
}
