<?php

namespace App\Services;

use App\Contracts\DatabaseDriverInterface;
use App\Contracts\SchemaDiscoveryInterface;

class DatabaseService
{
    protected ?DatabaseDriverInterface $driver = null;

    /**
     * Set the database driver.
     */
    public function setDriver(DatabaseDriverInterface $driver): self
    {
        $this->driver = $driver;
        return $this;
    }

    /**
     * Get the current driver.
     * 
     * @throws \Exception
     */
    public function getDriver(): DatabaseDriverInterface
    {
        if (!$this->driver) {
            throw new \Exception("Database driver not initialized.");
        }
        return $this->driver;
    }

    /**
     * Establish a connection.
     */
    public function connect(array $config): bool
    {
        return $this->getDriver()->connect($config);
    }

    /**
     * Get all databases.
     */
    public function getDatabases(): array
    {
        $driver = $this->getDriver();
        if ($driver instanceof SchemaDiscoveryInterface) {
            return $driver->getDatabases();
        }
        throw new \Exception("Driver does not support schema discovery.");
    }

    /**
     * Get all tables.
     */
    public function getTables(): array
    {
        $driver = $this->getDriver();
        if ($driver instanceof SchemaDiscoveryInterface) {
            return $driver->getTables();
        }
        throw new \Exception("Driver does not support schema discovery.");
    }

    /**
     * Get table schema.
     */
    public function getTableSchema(string $table): array
    {
        $driver = $this->getDriver();
        if ($driver instanceof SchemaDiscoveryInterface) {
            return $driver->getTableSchema($table);
        }
        throw new \Exception("Driver does not support schema discovery.");
    }

    /**
     * Get table data.
     */
    public function getTableData(string $table, int $limit = 100, int $offset = 0, array $filters = []): array
    {
        return $this->getDriver()->getTableData($table, $limit, $offset, $filters);
    }

    /**
     * Get table row count.
     */
    public function getTableCount(string $table, array $filters = []): int
    {
        return $this->getDriver()->getTableCount($table, $filters);
    }

    /**
     * Execute a raw SQL query.
     */
    public function executeQuery(string $sql, array $bindings = []): array
    {
        return $this->getDriver()->query($sql, $bindings);
    }

    /**
     * Export the database.
     */
    public function export(array $config, array $filters = []): string
    {
        return $this->getDriver()->export($config, $filters);
    }

    /**
     * Import the database.
     */
    public function import(array $config, string $filePath): bool
    {
        return $this->getDriver()->import($config, $filePath);
    }

    /**
     * Get database metadata.
     */
    public function getDatabaseMetadata(string $database): array
    {
        return $this->getDriver()->getDatabaseMetadata($database);
    }

    /**
     * Get table metadata.
     */
    public function getTableMetadata(string $database, string $table): array
    {
        return $this->getDriver()->getTableMetadata($database, $table);
    }

    /**
     * Truncate a table.
     */
    public function truncateTable(string $table): bool
    {
        return $this->getDriver()->truncateTable($table);
    }

    public function dropTable(string $table): bool
    {
        return $this->getDriver()->dropTable($table);
    }

    public function optimizeTable(string $table): bool
    {
        return $this->getDriver()->optimizeTable($table);
    }

    /**
     * Get metadata for all tables in a database.
     */
    public function getTablesMetadata(string $database): array
    {
        return $this->getDriver()->getTablesMetadata($database);
    }

    /**
     * Perform batch update on a table.
     */
    public function batchUpdate(string $table, array $changes): bool
    {
        return $this->getDriver()->batchUpdate($table, $changes);
    }

    /**
     * Create a new database.
     */
    public function createDatabase(string $name, string $charset = 'utf8mb4', string $collation = 'utf8mb4_unicode_ci'): bool
    {
        return $this->getDriver()->createDatabase($name, $charset, $collation);
    }
}
