<?php
namespace App\Database;

class JsonDatabase implements DatabaseInterface {
    protected $dataDir = '';
    protected $tenantId = '';

    public function __construct($tenantId = null) {
        $this->tenantId = $tenantId ?: (defined('TENANT_ID') ? TENANT_ID : 'everestburo');
        $this->dataDir = __DIR__ . '/../../data/tenants/' . $this->tenantId;
        
        if (!is_dir($this->dataDir)) {
            mkdir($this->dataDir, 0777, true);
        }
    }

    protected function getFilePath($table) {
        return $this->dataDir . '/' . $table . '.json';
    }

    protected function readData($table) {
        $file = $this->getFilePath($table);
        if (!file_exists($file)) {
            return [];
        }
        $content = file_get_contents($file);
        return json_decode($content, true) ?: [];
    }

    protected function writeData($table, array $data) {
        $file = $this->getFilePath($table);
        $content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        return file_put_contents($file, $content, LOCK_EX) !== false;
    }

    public function saveAll($table, array $data): bool {
        return $this->writeData($table, $data);
    }

    public function selectAll($table, array $criteria = []): array {
        $data = $this->readData($table);
        if (empty($criteria)) {
            return $data;
        }

        return array_values(array_filter($data, function($item) use ($criteria) {
            foreach ($criteria as $key => $value) {
                // Use array_key_exists so explicit null values are matched correctly
                if (!array_key_exists($key, $item)) {
                    // If key doesn't exist in item, only match if we're looking for null
                    if ($value !== null) {
                        return false;
                    }
                    continue;
                }

                if (is_array($value)) {
                    // Check if item value is in the given array of acceptable values
                    if (!in_array($item[$key], $value)) {
                        return false;
                    }
                } elseif ($item[$key] !== $value) {
                    return false;
                }
            }
            return true;
        }));
    }

    public function selectOne($table, array $criteria): ?array {
        $results = $this->selectAll($table, $criteria);
        return isset($results[0]) ? $results[0] : null;
    }

    public function insert($table, array $data): bool {
        $rows = $this->readData($table);
        
        // Ensure unique ID if not provided
        if (!isset($data['id'])) {
            $data['id'] = uniqid($table . '_');
        }
        
        $rows[] = $data;
        return $this->writeData($table, $rows);
    }

    public function update($table, array $criteria, array $data): bool {
        $rows = $this->readData($table);
        $updated = false;

        foreach ($rows as $index => &$item) {
            $match = true;
            foreach ($criteria as $key => $value) {
                if (!isset($item[$key]) || $item[$key] != $value) {
                    $match = false;
                    break;
                }
            }
            if ($match) {
                // Merge new data
                $item = array_merge($item, $data);
                $updated = true;
            }
        }

        if ($updated) {
            return $this->writeData($table, $rows);
        }
        return false;
    }

    public function delete($table, array $criteria): bool {
        $rows = $this->readData($table);
        $initialCount = count($rows);

        $rows = array_filter($rows, function($item) use ($criteria) {
            $match = true;
            foreach ($criteria as $key => $value) {
                if (!isset($item[$key]) || $item[$key] != $value) {
                    $match = false;
                    break;
                }
            }
            return !$match; // Keep items that DO NOT match delete criteria
        });

        $rows = array_values($rows); // Re-index array

        if (count($rows) !== $initialCount) {
            return $this->writeData($table, $rows);
        }
        return false;
    }
}
