<?php

declare(strict_types=1);

namespace App\Framework\Database\ValueObjects;

use App\Framework\Database\Validation\DatabaseIdentifierValidator;
use InvalidArgumentException;

/**
 * Value Object representing a database table name
 *
 * Provides type safety, validation, and SQL injection prevention for table names.
 * Ensures table names follow standard SQL naming conventions.
 *
 * Features:
 * - Alphanumeric validation with underscores
 * - SQL keyword detection
 * - Maximum length enforcement (64 chars - MySQL standard)
 * - Case-insensitive comparison
 * - Platform-specific quoting support
 */
final readonly class TableName
{
    private function __construct(
        public string $value
    ) {
        $this->validate();
    }

    /**
     * Create from string
     */
    public static function fromString(string $tableName): self
    {
        return new self($tableName);
    }

    /**
     * Convert to string
     */
    public function toString(): string
    {
        return $this->value;
    }

    /**
     * Magic __toString for convenient string conversion
     */
    public function __toString(): string
    {
        return $this->value;
    }

    /**
     * Compare for equality (case-insensitive)
     */
    public function equals(self $other): bool
    {
        return strcasecmp($this->value, $other->value) === 0;
    }

    /**
     * Check if table name matches pattern (case-insensitive)
     */
    public function matches(string $pattern): bool
    {
        return fnmatch($pattern, $this->value, FNM_CASEFOLD);
    }

    /**
     * Get quoted identifier for safe SQL usage
     *
     * Platform-specific quoting:
     * - MySQL: `table_name`
     * - PostgreSQL: "table_name"
     * - SQLite: "table_name"
     */
    public function quoted(string $platform = 'mysql'): string
    {
        return match (strtolower($platform)) {
            'mysql' => "`{$this->value}`",
            'postgresql', 'postgres', 'pgsql' => "\"{$this->value}\"",
            'sqlite' => "\"{$this->value}\"",
            default => "`{$this->value}`", // Default to MySQL style
        };
    }

    /**
     * Check if table name is a reserved SQL keyword
     */
    public function isReservedKeyword(): bool
    {
        return (new DatabaseIdentifierValidator())->isReservedKeyword($this->value);
    }

    /**
     * Get lowercase version (useful for case-insensitive comparisons)
     */
    public function toLower(): string
    {
        return strtolower($this->value);
    }

    /**
     * Check if table name starts with given prefix
     */
    public function hasPrefix(string $prefix): bool
    {
        return str_starts_with($this->value, $prefix);
    }

    /**
     * Remove prefix from table name
     */
    public function withoutPrefix(string $prefix): self
    {
        if (!$this->hasPrefix($prefix)) {
            return $this;
        }

        return new self(substr($this->value, strlen($prefix)));
    }

    /**
     * Add prefix to table name
     */
    public function withPrefix(string $prefix): self
    {
        return new self($prefix . $this->value);
    }

    /**
     * Validate table name
     *
     * @throws InvalidArgumentException if validation fails
     */
    private function validate(): void
    {
        (new DatabaseIdentifierValidator())->validate($this->value, 'table');
    }
}
