<?php
/**
 * 芋头CMS
 * ============================================================================
 * 版权所有 2016-2028 沅陵县乌托邦网络服务有限公司，并保留所有权利。
 * 网站地址: http://www.yutoucms.cn
 * ----------------------------------------------------------------------------
 * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
 * ============================================================================
 * Author: 芋头 <mxgsf@qq.com>
 * Date: 2026-5-20
 */



namespace Core\Db;

class DB
{
    private static $instance = null;
    private $pdo;
    private $config;
    
    private function __construct()
    {
        $this->config = require dirname(__DIR__) . '/db/config.php';
        $this->connect();
    }
    
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function connect()
    {
        $dsn = sprintf(
            "mysql:host=%s;port=%s;dbname=%s;charset=%s",
            $this->config['host'],
            $this->config['port'],
            $this->config['database'],
            $this->config['charset']
        );
        
        try {
            $this->pdo = new \PDO($dsn, $this->config['username'], $this->config['password'], [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
                \PDO::ATTR_EMULATE_PREPARES => false
            ]);
        } catch (\PDOException $e) {
            die("数据库连接失败: " . $e->getMessage());
        }
    }
    
    public function getPdo()
    {
        return $this->pdo;
    }
    
    /**
     * 执行查询
     */
    public function query($sql, $params = [])
    {
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }
    
    /**
     * 查询所有记录
     */
    public function fetchAll($sql, $params = [])
    {
        $stmt = $this->query($sql, $params);
        return $stmt->fetchAll();
    }
    
    /**
     * 查询单条记录
     */
    public function fetch($sql, $params = [])
    {
        $stmt = $this->query($sql, $params);
        return $stmt->fetch();
    }
    
    /**
     * 插入数据，返回最后插入ID
     */
    public function insert($table, $data)
    {
        $fields = array_keys($data);
        $placeholders = array_fill(0, count($fields), '?');

        $sql = sprintf(
            "INSERT INTO %s (%s) VALUES (%s)",
            $this->config['prefix'] . $table,
            implode(', ', $fields),
            implode(', ', $placeholders)
        );

        $this->query($sql, array_values($data));
        return $this->pdo->lastInsertId();
    }

    /**
     * 获取最后插入ID
     */
    public function lastInsertId()
    {
        return $this->pdo->lastInsertId();
    }

    /**
     * 更新数据
     */
    public function update($table, $data, $where, $whereParams = [])
    {
        $sets = [];
        $values = [];
        foreach ($data as $field => $val) {
            // PDO 对 null 参数会绑定成 NULL，但若字段不允许 NULL 且有无效默认值会导致错误
            // 改为直接用 IFNULL/COALESCE，或传字符串 '0000-00-00' 代替 null
            if ($val === null) {
                $sets[] = "{$field} = NULL";
            } else {
                $sets[] = "{$field} = ?";
                $values[] = $val;
            }
        }

        $sql = sprintf(
            "UPDATE %s SET %s WHERE %s",
            $this->config['prefix'] . $table,
            implode(', ', $sets),
            $where
        );

        $params = array_merge($values, $whereParams);
        $stmt = $this->query($sql, $params);
        return $stmt ? $stmt->rowCount() : 0;
    }

    /**
     * 删除数据
     */
    public function delete($table, $where, $params = [])
    {
        $sql = sprintf(
            "DELETE FROM %s WHERE %s",
            $this->config['prefix'] . $table,
            $where
        );

        $stmt = $this->query($sql, $params);
        return $stmt ? $stmt->rowCount() : 0;
    }

    /**
     * 获取表名（带前缀）
     */
    public function table($table)
    {
        return $this->config['prefix'] . $table;
    }
    
    /**
     * 获取配置
     */
    public function getConfig()
    {
        return $this->config;
    }
    
    /**
     * 开始事务
     */
    public function beginTransaction()
    {
        $this->pdo->beginTransaction();
    }
    
    /**
     * 提交事务
     */
    public function commit()
    {
        $this->pdo->commit();
    }
    
    /**
     * 回滚事务
     */
    public function rollBack()
    {
        $this->pdo->rollBack();
    }
}