<?php
namespace FleekDash\Models;

defined('ABSPATH') || exit;

// Load debug helpers
if (!function_exists('fleekdash_log_error')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

/**
 * Base Model Class
 *
 * Replacement for Eloquent Model with WordPress $wpdb
 * Provides simple CRUD operations without external dependencies
 */
abstract class BaseModel
{
    protected $wpdb;
    protected $table;
    protected $primaryKey = 'id';
    protected $fillable = [];
    protected $casts = [];
    protected $timestamps = true;

    public function __construct()
    {
        global $wpdb;
        $this->wpdb = $wpdb;

        // Add prefix to table if not already there
        if (!str_starts_with($this->table, $wpdb->prefix)) {
            $this->table = $wpdb->prefix . $this->table;
        }
    }

    /**
     * Find record by ID
     */
    public static function find($id)
    {
        $instance = new static();

        $result = $instance->wpdb->get_row($instance->wpdb->prepare(
            "SELECT * FROM {$instance->table} WHERE {$instance->primaryKey} = %d",
            $id
        ), ARRAY_A);

        return $result ? $instance->castAttributes($result) : null;
    }

    /**
     * Get all records
     */
    public static function all()
    {
        $instance = new static();

        $results = $instance->wpdb->get_results(
            "SELECT * FROM {$instance->table}",
            ARRAY_A
        );

        return array_map([$instance, 'castAttributes'], $results);
    }

    /**
     * Create new record
     */
    public static function create(array $data)
    {
        $instance = new static();
        $data = $instance->filterFillable($data);

        // Validate: Don't allow completely empty inserts
        if (empty($data) && !$instance->timestamps) {
            fleekdash_log_error('BaseModel::create() called with empty or non-fillable data on ' . get_called_class());
            return false;
        }

        if ($instance->timestamps) {
            $data['created_at'] = \current_time('mysql');
            $data['updated_at'] = \current_time('mysql');
        }

        $result = $instance->wpdb->insert($instance->table, $data);

        return $result ? $instance->wpdb->insert_id : false;
    }

    /**
     * Update record
     */
    public static function update($id, array $data)
    {
        $instance = new static();
        $data = $instance->filterFillable($data);

        if ($instance->timestamps) {
            $data['updated_at'] = \current_time('mysql');
        }

        return $instance->wpdb->update(
            $instance->table,
            $data,
            [$instance->primaryKey => $id]
        );
    }

    /**
     * Delete record
     */
    public static function delete($id)
    {
        $instance = new static();

        return $instance->wpdb->delete(
            $instance->table,
            [$instance->primaryKey => $id]
        );
    }

    /**
     * Simple where query
     */
    public static function where(string $column, $value)
    {
        $instance = new static();

        $results = $instance->wpdb->get_results($instance->wpdb->prepare(
            "SELECT * FROM {$instance->table} WHERE {$column} = %s",
            $value
        ), ARRAY_A);

        return array_map([$instance, 'castAttributes'], $results);
    }

    /**
     * Filter fillable attributes
     */
    protected function filterFillable(array $data): array
    {
        if (empty($this->fillable)) {
            return $data;
        }

        return array_intersect_key($data, array_flip($this->fillable));
    }

    /**
     * Cast attributes according to $casts property
     */
    protected function castAttributes(array $data): array
    {
        foreach ($this->casts as $key => $type) {
            if (!isset($data[$key])) {
                continue;
            }

            switch ($type) {
                case 'boolean':
                case 'bool':
                    $data[$key] = (bool) $data[$key];
                    break;
                case 'integer':
                case 'int':
                    $data[$key] = (int) $data[$key];
                    break;
                case 'float':
                case 'double':
                    $data[$key] = (float) $data[$key];
                    break;
                case 'array':
                case 'json':
                    $data[$key] = is_string($data[$key]) ? json_decode($data[$key], true) : $data[$key];
                    break;
                case 'string':
                    $data[$key] = (string) $data[$key];
                    break;
                default:
                    break;
            }
        }

        return $data;
    }

    /**
     * Get table name
     */
    public function getTable(): string
    {
        return $this->table;
    }

    /**
     * Get primary key
     */
    public function getPrimaryKey(): string
    {
        return $this->primaryKey;
    }

    /**
     * Check if the table exists in the database
     *
     * This method MUST be called before any query operations
     * to prevent "Table doesn't exist" errors during plugin activation
     * when migrations haven't run yet.
     *
     * @return bool True if table exists, false otherwise
     */
    public static function tableExists(): bool
    {
        $instance = new static();

        // Suppress errors during table existence check
        // This prevents "Table doesn't exist" errors from outputting during activation
        $suppress_errors = $instance->wpdb->suppress_errors(true);
        $show_errors = $instance->wpdb->show_errors;
        $instance->wpdb->show_errors = false;

        try {
            // Use SHOW TABLES which is more reliable than information_schema
            // and doesn't trigger WordPress wpdb error logging
            $result = $instance->wpdb->get_var($instance->wpdb->prepare(
                "SHOW TABLES LIKE %s",
                $instance->table
            ));

            return $result === $instance->table;
        } finally {
            // Restore error handling
            $instance->wpdb->suppress_errors($suppress_errors);
            $instance->wpdb->show_errors = $show_errors;
        }
    }

    /**
     * Safe find - returns null if table doesn't exist
     *
     * @param int $id Record ID
     * @return array|null
     */
    public static function safeFind($id)
    {
        if (!static::tableExists()) {
            return null;
        }
        return static::find($id);
    }

    /**
     * Safe all - returns empty array if table doesn't exist
     *
     * @return array
     */
    public static function safeAll(): array
    {
        if (!static::tableExists()) {
            return [];
        }
        return static::all();
    }
}
