<?php

declare(strict_types=1);

namespace App\Framework\Deployment\Ssl\ValueObjects;

use InvalidArgumentException;

/**
 * Domain Name Value Object with validation
 */
final readonly class DomainName
{
    private const int MAX_DOMAIN_LENGTH = 253;
    private const int MAX_LABEL_LENGTH = 63;

    public function __construct(public string $value)
    {
        $this->validate($value);
    }

    public static function fromString(string $domain): self
    {
        return new self($domain);
    }

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

    public function __toString(): string
    {
        return $this->value;
    }

    public function equals(self $other): bool
    {
        return strtolower($this->value) === strtolower($other->value);
    }

    public function isWildcard(): bool
    {
        return str_starts_with($this->value, '*.');
    }

    public function getLabels(): array
    {
        return explode('.', $this->value);
    }

    public function getTld(): string
    {
        $labels = $this->getLabels();
        return end($labels);
    }

    public function getSubdomain(): ?string
    {
        $labels = $this->getLabels();
        if (count($labels) > 2) {
            return $labels[0];
        }
        return null;
    }

    private function validate(string $domain): void
    {
        if (empty($domain)) {
            throw new InvalidArgumentException('Domain name cannot be empty');
        }

        if (strlen($domain) > self::MAX_DOMAIN_LENGTH) {
            throw new InvalidArgumentException(
                "Domain name exceeds maximum length of " . self::MAX_DOMAIN_LENGTH . " characters"
            );
        }

        // Remove wildcard prefix for validation
        $domainToValidate = str_starts_with($domain, '*.') ? substr($domain, 2) : $domain;

        // Validate domain format
        if (!preg_match('/^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i', $domainToValidate)) {
            throw new InvalidArgumentException("Invalid domain name format: {$domain}");
        }

        // Validate each label
        $labels = explode('.', $domainToValidate);
        foreach ($labels as $label) {
            if (strlen($label) > self::MAX_LABEL_LENGTH) {
                throw new InvalidArgumentException(
                    "Domain label '{$label}' exceeds maximum length of " . self::MAX_LABEL_LENGTH . " characters"
                );
            }

            if (str_starts_with($label, '-') || str_ends_with($label, '-')) {
                throw new InvalidArgumentException("Domain label cannot start or end with hyphen: {$label}");
            }
        }

        // Check for invalid characters
        if (preg_match('/[^a-z0-9.-]/i', $domainToValidate)) {
            throw new InvalidArgumentException("Domain contains invalid characters: {$domain}");
        }
    }
}
