<?php

namespace App\Models;

use PDO;
use Config\Database;
use Exception;
use PDOException;

class BaseModel
{
    protected static $table = '';

    public function __construct($data = [])
    {
        foreach ($data as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }

    protected static function getConnection()
    {
        return Database::getConnection();
    }

    /**
     * @return static[]|null
     */
    public static function getAll()
    {
        try {
            $db = self::getConnection();
            $query = "SELECT * FROM `" . static::$table . "`";
            $stmt = $db->query($query);
            $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $objects = [];

            foreach ($data as $row) {
                $objects[] = new static($row);
            }
            return $objects;

        } catch (PDOException $e) {
            error_log("Error en obtener registros: " . $e->getMessage());
            return null;
        }
    }

    /**
     * @return static[]|null
     */
    public static function getActives()
    {
        try {
            $db = self::getConnection();
            $query = "SELECT * FROM `" . static::$table . "` WHERE deleted_at IS NULL";
            $stmt = $db->query($query);
            $data = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $objects = [];
            foreach ($data as $row) {
                $objects[] = new static($row);
            }
            return $objects;

        } catch (PDOException $e) {
            error_log("Error en obtener registros: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Busca un registro por ID.
     * @param int $id
     * @return static|null
     */
    public static function find($id)
    {
        try {
            $db = self::getConnection();
            $query = "SELECT * FROM `" . static::$table . "` WHERE id = :id AND deleted_at IS NULL";

            $stmt = $db->prepare($query);
            $stmt->execute([':id' => $id]);
            $data = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($data) {

                $model = new static($data);
                return $model;
            }

            return null;
        } catch (PDOException $e) {
            error_log("Error en buscar registro: " . $e->getMessage());
            return null;
        }
    }

    
    /**
     * Busca un registro por un campo específico.
     * 
     * @param string $column Nombre de la columna a buscar.
     * @param mixed $value Valor a buscar en la columna.
     * @return static|null Retorna una instancia del modelo si encuentra un registro, de lo contrario, retorna null.
     */
    public static function findBy($column, $value)
    {
        try {
            $db = self::getConnection();
            $query = "SELECT * FROM `" . static::$table . "` WHERE $column = :value AND deleted_at IS NULL LIMIT 1";

            $stmt = $db->prepare($query);
            $stmt->execute([':value' => $value]);
            $data = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($data) {
                $model = new static($data);
                return $model;
            }

            return null;
        } catch (PDOException $e) {
            error_log("Error en la consulta findBy: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Busca un registro por múltiples columnas.
     *
     * @param array $conditions Un array asociativo ['columna' => 'valor', ...] con las condiciones de búsqueda.
     * @return static|null Retorna una instancia del modelo si encuentra un registro, de lo contrario, retorna null.
     */
    public static function findByMultiple(array $conditions)
    {
        try {
            $db = self::getConnection();

            $whereClauses = [];
            $params = [];
            foreach ($conditions as $column => $value) {
                if (is_array($value) && count($value) === 2) {
                    list($operator, $realValue) = $value;
                    if (!in_array($operator, ['=', '!=', '>', '>=', '<', '<='])) {
                        throw new Exception("Operador no soportado: $operator");
                    }
                    $whereClauses[] = "$column $operator :$column";
                    $params[":$column"] = $realValue;
                } elseif ($value === null) {
                    $whereClauses[] = "$column IS NULL";
                } else {
                    $whereClauses[] = "$column = :$column";
                    $params[":$column"] = $value;
                }
            }

            $whereClause = implode(" AND ", $whereClauses);
            $query = "SELECT * FROM `" . static::$table . "` WHERE $whereClause AND deleted_at IS NULL LIMIT 1";

            $stmt = $db->prepare($query);
            $stmt->execute($params);
            $data = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($data) {
                $model = new static($data);
                return $model;
            }

            return null;
        } catch (PDOException $e) {
            error_log("Error en la consulta findByMultiple: " . $e->getMessage());
            return null;
        }
    }

    public static function where($column, $value)
    {
        try {
            $db = self::getConnection();
            $query = "SELECT * FROM `" . static::$table . "` WHERE $column = :value AND deleted_at IS NULL";

            $stmt = $db->prepare($query);
            $stmt->execute([':value' => $value]);
            $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $models = [];
            foreach ($results as $data) {
                $models[] = new static($data);
            }

            return $models;
        } catch (PDOException $e) {
            error_log("Error en la consulta where: " . $e->getMessage());
            return [];
        }
    }


    public static function delete($id)
    {
        try {
            $db = self::getConnection();
            $query = "UPDATE `" . static::$table . "` SET deleted_at = NOW(), active = 0 WHERE id = :id";
            $stmt = $db->prepare($query);
            return $stmt->execute([':id' => $id]);

        } catch (PDOException $e) {
            error_log("Error al borrar registro: " . $e->getMessage());
            return null;
        }        
    }
}
