<?php
/**
 * @package Hafenstudios\Leadlotse
 */

namespace Hafenstudios\Leadlotse\Events;

use Hafenstudios\Leadlotse\Db\EntryRepository;

defined( 'ABSPATH' ) || exit;

/**
 * Kapazitaetslogik fuer Veranstaltungs-Anmeldungen (L-R1).
 *
 * Zaehlweise: jede Anmeldung belegt 1 + Begleitpersonen Plaetze. Es zaehlen
 * ALLE Entries des Formulars, auch noch unbestaetigte DOI-Anmeldungen - sonst
 * koennte die Veranstaltung zwischen Absenden und Bestaetigen ueberbucht
 * werden. Abgelaufene, unbestaetigte Anmeldungen raeumt der taegliche
 * Wartungs-Cron ohnehin ab (delete_expired_doi), die Plaetze werden dann
 * wieder frei.
 */
final class EventCapacity {

	private EntryRepository $entries;

	/**
	 * @param EntryRepository $entries Entry-Repository.
	 */
	public function __construct( EntryRepository $entries ) {
		$this->entries = $entries;
	}

	/**
	 * Sind die Veranstaltungs-Einstellungen aktiv?
	 *
	 * @param array<string, mixed> $definition Formular-Definition.
	 * @return bool
	 */
	public static function is_event( array $definition ): bool {
		return ! empty( $definition['settings']['event']['enabled'] );
	}

	/**
	 * Konfigurierte Kapazitaet (0 = unbegrenzt).
	 *
	 * @param array<string, mixed> $definition Formular-Definition.
	 * @return int
	 */
	public static function capacity( array $definition ): int {
		return absint( $definition['settings']['event']['capacity'] ?? 0 );
	}

	/**
	 * Feld-ID des Begleitpersonen-Felds: das erste Zahlenfeld der Definition.
	 *
	 * @param array<string, mixed> $definition Formular-Definition.
	 * @return string Leer, wenn keines existiert.
	 */
	public static function companions_field_id( array $definition ): string {
		foreach ( (array) ( $definition['fields'] ?? array() ) as $field ) {
			if ( is_array( $field ) && 'number' === (string) ( $field['type'] ?? '' ) ) {
				return (string) ( $field['id'] ?? '' );
			}
		}
		return '';
	}

	/**
	 * Personenzahl eines Entries (1 + Begleitpersonen).
	 *
	 * @param array<string, mixed> $values     Feldwerte des Entries.
	 * @param array<string, mixed> $definition Formular-Definition.
	 * @return int
	 */
	public static function persons( array $values, array $definition ): int {
		$field_id = self::companions_field_id( $definition );
		$extra    = '' !== $field_id ? absint( $values[ $field_id ] ?? 0 ) : 0;
		return 1 + $extra;
	}

	/**
	 * Bereits belegte Plaetze eines Formulars.
	 *
	 * @param int                  $form_id    Formular-ID.
	 * @param array<string, mixed> $definition Formular-Definition.
	 * @return int
	 */
	public function spots_taken( int $form_id, array $definition ): int {
		$taken = 0;
		foreach ( $this->entries->all_for_form( $form_id ) as $entry ) {
			$taken += self::persons( (array) ( $entry['field_values'] ?? array() ), $definition );
		}
		return $taken;
	}

	/**
	 * Ist die Veranstaltung fuer weitere $additional_persons Personen voll?
	 * Ohne aktive Veranstaltung oder ohne Kapazitaet (0) nie voll.
	 *
	 * @param int                  $form_id            Formular-ID.
	 * @param array<string, mixed> $definition         Formular-Definition.
	 * @param int                  $additional_persons Zusaetzlich benoetigte Plaetze.
	 * @return bool
	 */
	public function is_full( int $form_id, array $definition, int $additional_persons = 1 ): bool {
		if ( ! self::is_event( $definition ) ) {
			return false;
		}
		$capacity = self::capacity( $definition );
		if ( $capacity <= 0 ) {
			return false;
		}
		return $this->spots_taken( $form_id, $definition ) + max( 1, $additional_persons ) > $capacity;
	}

	/**
	 * Kapazitaetspruefung fuer die Submit-Pipeline.
	 *
	 * @param int                  $form_id    Formular-ID.
	 * @param array<string, mixed> $definition Formular-Definition.
	 * @param array<string, mixed> $values     Validierte Feldwerte des Submits.
	 * @return \WP_Error|null Fehler, wenn ausgebucht.
	 */
	public function check_submit( int $form_id, array $definition, array $values ) {
		if ( ! $this->is_full( $form_id, $definition, self::persons( $values, $definition ) ) ) {
			return null;
		}
		return new \WP_Error(
			'leadlotse_event_full',
			__( 'Diese Veranstaltung ist ausgebucht. Es sind leider keine Plaetze mehr frei.', 'leadlotse' ),
			array( 'status' => 409 )
		);
	}
}
