<?php
/**
 * Named timezone value object.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Domain\Shared;

/**
 * A valid launch timezone: IANA name or WordPress UTC offset.
 */
final class NamedTimezone {
	private string $name;
	/**
	 * Creates a supported launch timezone.
	 *
	 * @param string $name IANA timezone name or UTC offset.
	 */
	public function __construct( string $name ) {
		$name       = trim( $name );
		$this->name = $name;

		if ( ! self::isValid( $name ) ) {
			throw new \InvalidArgumentException( 'Timezone must be an IANA timezone or UTC offset.' );
		}
	}

	/**
	 * Returns whether a timezone name can be safely used for launch scheduling.
	 */
	public static function isValid( string $name ): bool {
		$name = trim( $name );

		if ( '' === $name ) {
			return false;
		}

		if ( in_array( $name, timezone_identifiers_list( \DateTimeZone::ALL_WITH_BC ), true ) ) {
			return true;
		}

		if ( 1 !== preg_match( '/^[+-](\d{2}):([0-5]\d)$/', $name, $matches ) ) {
			return false;
		}

		$hours   = (int) $matches[1];
		$minutes = (int) $matches[2];

		if ( $hours > 14 || ( 14 === $hours && 0 !== $minutes ) ) {
			return false;
		}

		try {
			new \DateTimeZone( $name );
		} catch ( \Exception $exception ) {
			return false;
		}

		return true;
	}

	/**
	 * Timezone name or offset.
	 */
	public function value(): string {
		return $this->name;
	}

	/**
	 * Native timezone.
	 */
	public function native(): \DateTimeZone {
		return new \DateTimeZone( $this->name );
	}

	/**
	 * String conversion.
	 */
	public function __toString(): string {
		return $this->name;
	}
}
