<?php
namespace ContingentParser\Database;

use ContingentParser\Logger\DatabaseLogger;
use Symfony\Component\Yaml\Yaml;
use PDOException;
use PDO;

final class Database
{
    private PDO $_pdo;
    private static $_logFile = 'log/database.log';
    private DatabaseConfig $_databaseConfig;
    private DatabaseLogger $_logger;
    /**
     * Конструктор
     * @param \ContingentParser\Database\DatabaseConfig $config
     * Конфигурация подключения к базе данных
     */
    public function __construct(DatabaseConfig $config)
    {
        $this->_logger = new DatabaseLogger(self::$_logFile);
        $this->_databaseConfig = $config;
        try {
            $dsn = $this->_databaseConfig->getDsn();
            $username = $this->_databaseConfig->getUsername();
            $password = $this->_databaseConfig->getPassword();
            $this->_pdo = new PDO(
                $dsn, 
                $username, 
                $password, 
                [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
            );
            $message = "Подключение к {$this->_databaseConfig->getDBName()} успешно!";
            $this->_logger->log($message);
        } catch (PDOException $e) {
            $message = "Ошибка подключения к {$this->_databaseConfig->getDBName()}: {$e->getMessage()}";
            $this->_logger->log($message);
        }
    }
    /**
     * Сообщение о разрыве соединения
     */
    public function __destruct()
    {
        $message = "Подключение к {$this->_databaseConfig->getDBName()} прервано!";
        $this->_logger->log($message);
    }
    /**
     * Выборка данных из базы
     * @param string $sql
     * SQL-запрос
     * @param array $params
     * Параметры запроса
     * @return array
     */
    public function select(string $sql, array $params = []) : array
    {
        try {
            $stmt = $this->_pdo->prepare($sql);
            if (!empty($params)) {
                for ($i = 0; $i < count($params); $i++) {
                    $stmt->bindParam(":v".($i+1), $params[$i]);
                }
            }
            $stmt->execute();
            $array = $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            $message = "Ошибка запроса: " . $e->getMessage();
            $this->_logger->log($message);
        } finally {
            return $array;
        }
    }
    /**
     * Добавление данных в базу
     * @param string $sql
     *  SQL-запрос
     * @param array $params
     * Параметры запроса
     * @return void
     */
    public function insert(string $sql, array $params)
    {
        try {
            $stmt = $this->_pdo->prepare($sql);
            $count = 1;
            $size = count($params[0]);
            foreach ($params as $param) {
                for ($i = $count; $i <= $size; $i++) { 
                    $param = array_values($param);
                    $stmt->bindParam(":v$i", $param[$i-$count]);
                }
                $count += count($param);
                $size += count($param);
            }
            $stmt->execute();
            $this->_logger->log("Запрос выполнен успешно!");
        } catch (PDOException $e) {
            $message = "Ошибка запроса:" . $e->getMessage();
            $this->_logger->log($message);
            // При ошибке запроса сохраняем валидные данные в yaml-файл
            if ($e->getCode() === "HY000") {
                $yaml = Yaml::dump($params);
                file_put_contents('not-recorded-in-db.yaml', $yaml, FILE_APPEND);
            }
        }
    }
    /**
     * Обновление данных в базе
     * @param string $sql
     * SQL-запрос
     * @param array $params
     * Параметры запроса
     * @return void
     */
    public function update(string $sql, array $params)
    {
        try {
            $stmt = $this->_pdo->prepare($sql);
            $count = count($params);
           for ($i = 0; $i < $count; $i++) {
                $stmt->bindParam(":v".($i+1), $params[$i]);
            }
            // $stmt->execute();
            $this->_logger->log("Запрос выполнен успешно!");
        } catch (PDOException $e) {
            $message = "Ошибка запроса:" . $e->getMessage();
            $this->_logger->log($message);
        }
    }
}