<?php

namespace Core;

use PDO;
use PDOException;

class Database
{
    private $statement;
    protected $db;
    protected $table;
    protected $id;

    public function __construct()
    {
        try {
            $this->db = new PDO(constant('DB_DRIVER') . ':host=' . constant('DB_HOST') . ';dbname=' . constant('BASEDATOS'), constant('DB_USUARIO'), constant('DB_PASS'), [
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
                PDO::ATTR_CASE => PDO::CASE_LOWER,
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_ORACLE_NULLS => PDO::NULL_EMPTY_STRING,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
            ]);
        } catch (PDOException $e) {
            die('Error al conectarse a la base de datos');
        }

        return $this->db;
    }

    public function consultar(string $sql)
    {
        $this->statement = $this->db->prepare($sql);
        return $this;
    }

    public function run()
    {
        return $this->statement->execute();
    }

    public function all()
    {
        $this->run();
        return $this->statement->fetchAll();
    }

    public function row()
    {
        $this->run();
        return $this->statement->fetch();
    }

    public function count()
    {
        $this->run();
        return $this->statement->rowCount();
    }

    public function transactionBegin()
    {
        $this->db->beginTransaction();
    }

    public function transactionCommit()
    {
        $this->db->commit();
    }

    public function transactionRollBack()
    {
        $this->db->rollBack();
    }

    public function ultimoId()
    {
        return $this->db->lastInsertId();
    }

    public function existeDiferenteDeID($id_valor, $columna, $valor): bool
    {
        $res = $this->db->prepare("SELECT $this->id FROM $this->table WHERE $this->id != :p AND $columna = :$columna");
        $res->bindParam(':p', $id_valor);
        $res->bindParam(':' . $columna, $valor);
        $res->execute();
        return ($res->rowCount() >= 1) ? true : false;
    }

    public function existe(string $columna, $valor): bool
    {
        $res = $this->db->prepare("SELECT $this->id FROM $this->table WHERE $columna = :$columna");
        $res->bindParam(':' . $columna, $valor);
        $res->execute();
        return ($res->rowCount() >= 1) ? true : false;
    }

    public function todos(): array
    {
        $res = $this->db->prepare("SELECT * FROM $this->table");
        $res->execute();
        return $res->fetchAll();
    }

    public function obtener(int $id_valor)
    {
        $res = $this->db->prepare("SELECT * FROM $this->table WHERE $this->id = :p");
        $res->bindParam(':p', $id_valor);
        $res->execute();
        return $res->fetch();
    }

    public function where(array $columnas, bool $mixed = false)
    {
        $parametros = '';

        foreach ($columnas as $columna => $valor) {
            $ultimo_param = substr($columna, -2);
            if ($ultimo_param == '<>' || $ultimo_param == '!=') {
                $campo = substr($columna, 0, -2);
                $parametros .= "$campo $ultimo_param :$campo AND ";
            } else {
                $parametros .= "$columna = :$columna AND ";
            }
        }

        $parametros = trim($parametros, ' AND ');

        $res = $this->db->prepare("SELECT * FROM $this->table WHERE $parametros");

        foreach ($columnas as $columna => &$valor) {
            $ultimo_param = substr($columna, -2);
            if ($ultimo_param == '<>' || $ultimo_param == '!=') {
                $campo = substr($columna, 0, -2);
                $res->bindParam(":$campo", $valor);
            } else {
                $res->bindParam(":$columna", $valor);
            }
        }

        $res->execute();
        if ($mixed) {
            $result = $res->fetch();
        } else {
            $result = $res->fetchAll();
        }
        return $result;
    }

    public function guardar(array $data, $no_devolver_id = false, string $tabla = '')
    {
        $columns = array_keys($data);
        $params  = join(', :', $columns);
        $params  = ':' . $params;
        $columns = join(', ', $columns);

        if ($tabla !== '') {
            $this->table = $tabla;
        }

        $query   = "INSERT INTO $this->table ($columns) VALUES ($params)";

        $res = $this->db->prepare($query);

        foreach ($data as $key => &$val) {
            $res->bindParam(':' . $key, $val);
        }

        if ($no_devolver_id == true) {
            return ($res->execute()) ?  true : false;
        } else {
            return ($res->execute()) ?  $this->db->lastInsertId() : false;
        }
    }

    public function editar(int $id_valor, array $data, string $tabla = '', string $id_tabla = ''): bool
    {
        $params = '';
        $columns = array_keys($data);

        foreach ($columns as $columna) {
            $params .= $columna . ' = :' . $columna . ',';
        }

        $params = trim($params, ',');

        if ($tabla !== '' && $id_tabla !== '') {
            $this->table = $tabla;
            $this->id = $id_tabla;
        }

        $res = $this->db->prepare("UPDATE $this->table SET $params WHERE $this->id = $id_valor");

        foreach ($data as $key => &$val) {
            $res->bindParam(':' . $key, $val);
        }

        return ($res->execute()) ? true : false;
    }

    public function eliminar(int $id_valor): bool
    {
        $res = $this->db->prepare("DELETE FROM $this->table WHERE $this->id = :p");
        $res->bindParam(':p', $id_valor, PDO::PARAM_INT);
        return ($res->execute())  ? true : false;
    }
}
