<?php

declare(strict_types=1);

namespace App\Framework\Core\ValueObjects;

use InvalidArgumentException;

/**
 * Represents a city name with optional state/province
 * Immutable value object for address handling
 */
final readonly class City
{
    public function __construct(
        public string $name,
        public ?string $state = null,
        public ?CountryCode $country = null
    ) {
        if (trim($name) === '') {
            throw new InvalidArgumentException('City name cannot be empty');
        }
    }

    public static function create(string $name, ?string $state = null, ?CountryCode $country = null): self
    {
        return new self($name, $state, $country);
    }

    public function withState(string $state): self
    {
        return new self($this->name, $state, $this->country);
    }

    public function withCountry(CountryCode $country): self
    {
        return new self($this->name, $this->state, $country);
    }

    public function withoutState(): self
    {
        return new self($this->name, null, $this->country);
    }

    public function format(bool $includeState = true, bool $includeCountry = false): string
    {
        $formatted = $this->name;

        if ($includeState && $this->state !== null && trim($this->state) !== '') {
            $formatted .= ', ' . $this->state;
        }

        if ($includeCountry && $this->country !== null) {
            $formatted .= ', ' . ($this->country->getCountryName() ?? $this->country->value);
        }

        return $formatted;
    }

    public function getDisplayName(): string
    {
        return $this->format(true, false);
    }

    public function getFullName(): string
    {
        return $this->format(true, true);
    }

    public function hasState(): bool
    {
        return $this->state !== null && trim($this->state) !== '';
    }

    public function hasCountry(): bool
    {
        return $this->country !== null;
    }

    public function equals(self $other): bool
    {
        return $this->name === $other->name
            && $this->state === $other->state
            && (
                ($this->country === null && $other->country === null) ||
                ($this->country !== null && $other->country !== null && $this->country->value === $other->country->value)
            );
    }

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

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

    public function toArray(): array
    {
        return [
            'name' => $this->name,
            'state' => $this->state,
            'country' => $this->country?->value,
            'display_name' => $this->getDisplayName(),
            'full_name' => $this->getFullName(),
        ];
    }

    public static function fromArray(array $data): self
    {
        $country = isset($data['country'])
            ? CountryCode::fromString($data['country'])
            : null;

        return new self(
            $data['name'],
            $data['state'] ?? null,
            $country
        );
    }
}
