<?php
/**
 * Immutable value object representing a country-to-form-to-account routing rule.
 *
 * @since   1.0.0
 * @package DonationRouter
 */

declare( strict_types=1 );
namespace DonationRouter;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Encapsulates a single country routing rule.
 *
 * Determines which PayPal account and donation form to use for donors from a
 * given country. Use {@see Country_Routing::from_database_row()} to construct
 * from a DB result.
 *
 * @since 1.0.0
 */
class Country_Routing {

	/**
	 * Construct a Country_Routing value object.
	 *
	 * @since 1.0.0
	 *
	 * @param int|null           $id                  Database row ID; null for unsaved records.
	 * @param string             $country_code         ISO 3166-1 alpha-2 code (e.g. "US").
	 * @param int                $form_id              GiveWP form post ID (positive integer).
	 * @param int                $account_id           FK to ador_accounts (positive integer).
	 * @param string             $display_label        Human-readable country label shown in the modal.
	 * @param string|null        $display_description  Optional supplementary text (e.g. tax-deductibility note).
	 * @param int                $sort_order           Ascending display order in the country selector.
	 * @param bool               $is_active            Whether this rule is currently applied.
	 * @param \DateTimeImmutable $created_at           Record creation timestamp.
	 * @param \DateTimeImmutable $updated_at           Record last-update timestamp.
	 *
	 * @throws \InvalidArgumentException  When country_code is invalid or form_id / account_id are not positive.
	 */
	public function __construct(
		public readonly int|null $id,
		public readonly string $country_code,
		public readonly int $form_id,
		public readonly int $account_id,
		public readonly string $display_label,
		public readonly string|null $display_description,
		public readonly int $sort_order,
		public readonly bool $is_active,
		public readonly \DateTimeImmutable $created_at,
		public readonly \DateTimeImmutable $updated_at,
	) {
		if ( 1 !== preg_match( '/^[A-Z]{2}$/', $this->country_code ) ) {
			throw new \InvalidArgumentException(
				'country_code must be an ISO 3166-1 alpha-2 code (two uppercase letters).'
			);
		}

		if ( $this->form_id <= 0 ) {
			throw new \InvalidArgumentException( 'form_id must be a positive integer.' );
		}

		if ( $this->account_id <= 0 ) {
			throw new \InvalidArgumentException( 'account_id must be a positive integer.' );
		}
	}

	/**
	 * Construct from a raw database row.
	 *
	 * @since 1.0.0
	 *
	 * @param  array<string,mixed> $row  Associative row from wpdb.
	 *
	 * @return self
	 */
	public static function from_database_row( array $row ): self {
		$created_at = \DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', (string) $row['created_at'] );
		$updated_at = \DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', (string) $row['updated_at'] );

		return new self(
			id: isset( $row['id'] ) ? (int) $row['id'] : null,
			country_code: (string) $row['country_code'],
			form_id: (int) $row['form_id'],
			account_id: (int) $row['account_id'],
			display_label: (string) $row['display_label'],
			display_description: isset( $row['display_description'] ) ? (string) $row['display_description'] : null,
			sort_order: (int) $row['sort_order'],
			is_active: (bool) $row['is_active'],
			created_at: $created_at instanceof \DateTimeImmutable ? $created_at : new \DateTimeImmutable(),
			updated_at: $updated_at instanceof \DateTimeImmutable ? $updated_at : new \DateTimeImmutable(),
		);
	}

	/**
	 * Serialise to an array for JSON output (e.g. the country selector popup).
	 *
	 * @since 1.0.0
	 *
	 * @return array<string,mixed>
	 */
	public function to_array(): array {
		return array(
			'id'                  => $this->id,
			'country_code'        => $this->country_code,
			'form_id'             => $this->form_id,
			'account_id'          => $this->account_id,
			'display_label'       => $this->display_label,
			'display_description' => $this->display_description,
			'sort_order'          => $this->sort_order,
			'is_active'           => $this->is_active,
			'created_at'          => $this->created_at->format( 'Y-m-d H:i:s' ),
			'updated_at'          => $this->updated_at->format( 'Y-m-d H:i:s' ),
		);
	}
}
