<?php
require_once __DIR__ . '/Database.php';

abstract class BaseModel {
    protected $db;
    protected $table;
    protected $primaryKey = 'id';

    public function __construct() {
        $this->db = Database::getInstance();
    }

    public function find($id) {
        $stmt = $this->db->prepare("SELECT * FROM {$this->table} WHERE {$this->primaryKey} = ? LIMIT 1");
        $stmt->execute([$id]);
        return $stmt->fetch();
    }

    public function all() {
        $stmt = $this->db->query("SELECT * FROM {$this->table}");
        return $stmt->fetchAll();
    }

    public function getTotalCount() {
        $stmt = $this->db->query("SELECT COUNT(*) FROM {$this->table}");
        return $stmt->fetchColumn();
    }

    public function insert($data) {
        $keys = array_keys($data);
        $fields = implode(', ', $keys);
        $placeholders = implode(', ', array_fill(0, count($keys), '?'));
        
        $sql = "INSERT INTO {$this->table} ({$fields}) VALUES ({$placeholders})";
        $stmt = $this->db->prepare($sql);
        $stmt->execute(array_values($data));
        
        return $this->db->lastInsertId();
    }

    public function update($id, $data) {
        if (empty($data)) return false;
        
        $fields = '';
        $values = [];
        foreach ($data as $key => $value) {
            $fields .= "{$key} = ?, ";
            $values[] = $value;
        }
        $fields = rtrim($fields, ', ');
        $values[] = $id;

        $sql = "UPDATE {$this->table} SET {$fields} WHERE {$this->primaryKey} = ?";
        $stmt = $this->db->prepare($sql);
        return $stmt->execute($values);
    }

    public function delete($id) {
        $sql = "DELETE FROM {$this->table} WHERE {$this->primaryKey} = ?";
        $stmt = $this->db->prepare($sql);
        return $stmt->execute([$id]);
    }

    public function paginate($page = 1, $perPage = 20, $conditions = [], $orderBy = 'id DESC') {
        $offset = ($page - 1) * $perPage;
        $whereSql = '';
        $params = [];
        
        if (!empty($conditions)) {
            $whereParts = [];
            foreach ($conditions as $key => $value) {
                $whereParts[] = "{$key} = ?";
                $params[] = $value;
            }
            $whereSql = "WHERE " . implode(" AND ", $whereParts);
        }

        // Get total count
        $countSql = "SELECT COUNT(*) FROM {$this->table} {$whereSql}";
        $countStmt = $this->db->prepare($countSql);
        $countStmt->execute($params);
        $total = $countStmt->fetchColumn();

        // Get items
        $sql = "SELECT * FROM {$this->table} {$whereSql} ORDER BY {$orderBy} LIMIT ? OFFSET ?";
        $stmt = $this->db->prepare($sql);
        
        // Bind params manually because LIMIT/OFFSET require integers
        $paramIndex = 1;
        foreach ($params as $param) {
            $stmt->bindValue($paramIndex++, $param);
        }
        $stmt->bindValue($paramIndex++, (int)$perPage, PDO::PARAM_INT);
        $stmt->bindValue($paramIndex, (int)$offset, PDO::PARAM_INT);
        $stmt->execute();
        
        return [
            'data' => $stmt->fetchAll(),
            'total' => $total
        ];
    }

    public function searchPaginate($page = 1, $perPage = 20, $searchFields = [], $searchTerm = '', $filters = [], $orderBy = 'id DESC') {
        $offset = ($page - 1) * $perPage;
        $whereParts = [];
        $params = [];
        
        if (!empty($searchTerm) && !empty($searchFields)) {
            $searchParts = [];
            foreach ($searchFields as $field) {
                $searchParts[] = "{$field} LIKE ?";
                $params[] = "%$searchTerm%";
            }
            $whereParts[] = "(" . implode(" OR ", $searchParts) . ")";
        }

        foreach ($filters as $key => $value) {
            if ($value !== '' && $value !== null) {
                if (is_array($value)) {
                    // Range filter like ['date_from' => '2023-01-01', 'date_to' => '2023-12-31']
                    if (isset($value['start'])) {
                        $whereParts[] = "{$key} >= ?";
                        $params[] = $value['start'];
                    }
                    if (isset($value['end'])) {
                        $whereParts[] = "{$key} <= ?";
                        $params[] = $value['end'];
                    }
                } else {
                    $whereParts[] = "{$key} = ?";
                    $params[] = $value;
                }
            }
        }

        $whereSql = !empty($whereParts) ? "WHERE " . implode(" AND ", $whereParts) : "";

        // Count
        $countSql = "SELECT COUNT(*) FROM {$this->table} {$whereSql}";
        $countStmt = $this->db->prepare($countSql);
        $countStmt->execute($params);
        $total = $countStmt->fetchColumn();

        // Items
        $sql = "SELECT * FROM {$this->table} {$whereSql} ORDER BY {$orderBy} LIMIT ? OFFSET ?";
        $stmt = $this->db->prepare($sql);
        
        $paramIndex = 1;
        foreach ($params as $param) {
            $stmt->bindValue($paramIndex++, $param);
        }
        $stmt->bindValue($paramIndex++, (int)$perPage, PDO::PARAM_INT);
        $stmt->bindValue($paramIndex++, (int)$offset, PDO::PARAM_INT);
        $stmt->execute();
        
        return [
            'data' => $stmt->fetchAll(),
            'total' => $total
        ];
    }

    protected function logAction($action, $targetId = null, $details = null) {
        $data = [
            'admin_id' => $_SESSION['admin_id'] ?? null,
            'action' => $action,
            'target_type' => $this->table,
            'target_id' => $targetId,
            'details' => is_array($details) ? json_encode($details) : $details,
            'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null
        ];
        
        $keys = array_keys($data);
        $fields = implode(', ', $keys);
        $placeholders = implode(', ', array_fill(0, count($keys), '?'));
        $sql = "INSERT INTO audit_logs ({$fields}) VALUES ({$placeholders})";
        $stmt = $this->db->prepare($sql);
        return $stmt->execute(array_values($data));
    }
}
