<?php
namespace App\Models;

use App\Database\JsonDatabase;

abstract class Model {
    protected static $db;
    protected $attributes = [];

    public function __construct(array $attributes = []) {
        $this->attributes = $attributes;
    }

    public static function getDb() {
        if (!self::$db) {
            self::$db = new JsonDatabase();
        }
        return self::$db;
    }

    public function __get($key) {
        return isset($this->attributes[$key]) ? $this->attributes[$key] : null;
    }

    public function __isset($key) {
        return isset($this->attributes[$key]);
    }

    public function __set($key, $value) {
        $this->attributes[$key] = $value;
    }

    public function toArray() {
        return $this->attributes;
    }

    public static function all(array $criteria = []) {
        $db = self::getDb();
        $table = static::getTable();
        $rows = $db->selectAll($table, $criteria);
        
        $instances = [];
        foreach ($rows as $row) {
            $instances[] = new static($row);
        }
        return $instances;
    }

    public static function find($id): ?self {
        $db = self::getDb();
        $table = static::getTable();
        $row = $db->selectOne($table, ['id' => $id]);
        return $row ? new static($row) : null;
    }

    public static function findBy(array $criteria): ?self {
        $db = self::getDb();
        $table = static::getTable();
        $row = $db->selectOne($table, $criteria);
        return $row ? new static($row) : null;
    }

    public function save() {
        $db = self::getDb();
        $table = static::getTable();
        
        if (isset($this->attributes['id'])) {
            return $db->update($table, ['id' => $this->attributes['id']], $this->attributes);
        } else {
            $this->attributes['id'] = uniqid($table . '_');
            return $db->insert($table, $this->attributes);
        }
    }

    public function updateBy(array $criteria) {
        $db = self::getDb();
        $table = static::getTable();
        return $db->update($table, $criteria, $this->attributes);
    }

    public function delete() {
        if (!isset($this->attributes['id'])) {
            return false;
        }
        $db = self::getDb();
        $table = static::getTable();
        return $db->delete($table, ['id' => $this->attributes['id']]);
    }

    abstract static protected function getTable(): string;
}
