<?php
/**
 * Base Migration Grammar Class
 * 
 * @package Licenzo\Framework\Database\Migration\Grammar
 */

namespace Licenzo\Framework\Database\Migration\Grammar;

use Licenzo\Framework\Database\Migration\Connection;
use Licenzo\Framework\Database\Migration\Sql;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Abstract Base Migration Grammar Class
 */
abstract class Grammar
{
    /**
     * Database connection
     *
     * @var Connection
     */
    protected $connection;

    /**
     * Create a new grammar instance
     *
     * @param Connection $connection
     */
    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
    }

    /**
     * Compile a create table statement
     *
     * @param string $table
     * @param array $columns
     * @param array $indexes
     * @return Sql
     */
    abstract public function compileCreateTable($table, array $columns, array $indexes = []);

    /**
     * Compile a drop table statement
     *
     * @param string $table
     * @return Sql
     */
    abstract public function compileDropTable($table);

    /**
     * Compile an alter table statement
     *
     * @param string $table
     * @param array $operations
     * @return Sql
     */
    abstract public function compileAlterTable($table, array $operations);

    /**
     * Compile a rename table statement
     *
     * @param string $from
     * @param string $to
     * @return Sql
     */
    abstract public function compileRenameTable($from, $to);

    /**
     * Compile a truncate table statement
     *
     * @param string $table
     * @return Sql
     */
    abstract public function compileTruncateTable($table);

    /**
     * Compile an insert statement
     *
     * @param string $table
     * @param array $data
     * @return Sql
     */
    public function compileInsert($table, array $data)
    {
        $tableName = $this->getTableName($table);
        $columns = implode(', ', array_keys($data));
        $values = "'" . implode("', '", array_values($data)) . "'";
        $sql = "INSERT INTO {$tableName} ({$columns}) VALUES ({$values});";
        
        return Sql::raw($sql, ['table' => $table, 'data' => $data]);
    }

    /**
     * Compile an update statement
     *
     * @param string $table
     * @param array $data
     * @param array $where
     * @return Sql
     */
    public function compileUpdate($table, array $data, array $where)
    {
        $tableName = $this->getTableName($table);
        
        $setParts = [];
        foreach ($data as $column => $value) {
            $setParts[] = "{$column} = '{$value}'";
        }
        $setClause = implode(', ', $setParts);
        
        $whereParts = [];
        foreach ($where as $column => $value) {
            $whereParts[] = "{$column} = '{$value}'";
        }
        $whereClause = implode(' AND ', $whereParts);
        
        $sql = "UPDATE {$tableName} SET {$setClause} WHERE {$whereClause};";
        
        return Sql::raw($sql, ['table' => $table, 'data' => $data, 'where' => $where]);
    }

    /**
     * Compile a delete statement
     *
     * @param string $table
     * @param array $where
     * @return Sql
     */
    public function compileDelete($table, array $where)
    {
        $tableName = $this->getTableName($table);
        
        $whereParts = [];
        foreach ($where as $column => $value) {
            $whereParts[] = "{$column} = '{$value}'";
        }
        $whereClause = implode(' AND ', $whereParts);
        
        $sql = "DELETE FROM {$tableName} WHERE {$whereClause};";
        
        return Sql::raw($sql, ['table' => $table, 'where' => $where]);
    }

    /**
     * Get full table name with prefix
     *
     * @param string $table
     * @return string
     */
    protected function getTableName($table)
    {
        return $this->connection->getPrefix() . $table;
    }

    /**
     * Get charset collate string
     *
     * @return string
     */
    protected function getCharsetCollate()
    {
        return $this->connection->getCharsetCollate();
    }

    /**
     * Build index definition from array or string
     *
     * @param mixed $index
     * @return string
     */
    protected function buildIndexDefinition($index)
    {
        if (is_string($index)) {
            return $index;
        }
        
        if (is_array($index) && isset($index['type']) && isset($index['name']) && isset($index['columns'])) {
            $columns = is_array($index['columns']) ? implode(', ', $index['columns']) : $index['columns'];
            return "{$index['type']} `{$index['name']}` ({$columns})";
        }
        
        return '';
    }

    /**
     * Wrap value in quotes if it's a string
     *
     * @param mixed $value
     * @return string
     */
    protected function wrapValue($value)
    {
        if (is_string($value)) {
            return "'{$value}'";
        }
        
        if (is_null($value)) {
            return 'NULL';
        }
        
        if (is_bool($value)) {
            return $value ? '1' : '0';
        }
        
        return (string) $value;
    }

    /**
     * Wrap identifier in backticks
     *
     * @param string $identifier
     * @return string
     */
    protected function wrapIdentifier($identifier)
    {
        return "`{$identifier}`";
    }

    /**
     * Get database type
     *
     * @return string
     */
    protected function getDatabaseType()
    {
        return $this->connection->getType();
    }

    /**
     * Check if database is MySQL
     *
     * @return bool
     */
    protected function isMysql()
    {
        return $this->connection->isMysql();
    }

    /**
     * Check if database is SQLite
     *
     * @return bool
     */
    protected function isSqlite()
    {
        return $this->connection->isSqlite();
    }
}
