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

namespace Hafenstudios\Kurato\Booking;

use Hafenstudios\Core\Core;
use Hafenstudios\Kurato\Db\BookingRepository;
use Hafenstudios\Kurato\Db\BookingTypeRepository;
use Hafenstudios\Kurato\Db\ContactRepository;
use Hafenstudios\Kurato\Db\HostRepository;

defined( 'ABSPATH' ) || exit;

/**
 * Erinnerungs-Cron des Buchungsmoduls (K5c, K5-KONZEPT Abschnitt 5).
 *
 * Ein stuendlicher WP-Cron (Hook {@see HOOK}, geplant im Installer) sucht die
 * confirmed-Buchungen, deren Start im Fenster [jetzt + (reminder_hours - 1) h,
 * jetzt + reminder_hours) liegt und die noch keine Erinnerung erhalten haben
 * (reminder_sent = 0, K5a). Der Besucher wird erinnert; das Flag
 * `reminder_sent` wird erst NACH erfolgreichem Versand gesetzt (Idempotenz,
 * Muster WelcomeMailService: ein spaeterer Lauf holt einen fehlgeschlagenen
 * Versand nach). Die Host-Erinnerung haengt am Setting `booking.reminder_host`
 * (Default true, Inhaber-Entscheidung K5); ihr Ergebnis beeinflusst das Flag
 * nicht. `booking.reminder_hours = 0` schaltet die Erinnerung ganz aus.
 *
 * Nicht final; `config()` ist Test-Seam.
 */
class BookingReminders {

	public const HOOK = 'kurato_booking_reminders';

	private BookingRepository $bookings;

	private HostRepository $hosts;

	private BookingTypeRepository $types;

	private ContactRepository $contacts;

	private BookingMailer $mailer;

	/**
	 * @param BookingRepository     $bookings Buchungs-Repository.
	 * @param HostRepository        $hosts    Host-Repository.
	 * @param BookingTypeRepository $types    Terminarten-Repository.
	 * @param ContactRepository     $contacts Kontakt-Repository.
	 * @param BookingMailer         $mailer   Transaktionsmailer.
	 */
	public function __construct( BookingRepository $bookings, HostRepository $hosts, BookingTypeRepository $types, ContactRepository $contacts, BookingMailer $mailer ) {
		$this->bookings = $bookings;
		$this->hosts    = $hosts;
		$this->types    = $types;
		$this->contacts = $contacts;
		$this->mailer   = $mailer;
	}

	/**
	 * Verdrahtet den Cron-Hook.
	 *
	 * @return void
	 */
	public function register(): void {
		add_action( self::HOOK, array( $this, 'run' ) );
	}

	/**
	 * Verarbeitet einen Erinnerungs-Durchlauf.
	 *
	 * @param int $now_ts "Jetzt" als Unix-Zeit (0 = time()).
	 * @return int Anzahl der an Besucher versendeten Erinnerungen.
	 */
	public function run( int $now_ts = 0 ): int {
		$config = $this->config();
		$hours  = (int) $config['reminder_hours'];
		if ( $hours <= 0 ) {
			return 0; // Erinnerung aus.
		}

		$now_ts    = $now_ts > 0 ? $now_ts : time();
		$from_ts   = $now_ts + ( $hours - 1 ) * HOUR_IN_SECONDS;
		$to_ts     = $now_ts + $hours * HOUR_IN_SECONDS;
		$from_utc  = gmdate( 'Y-m-d H:i:s', $from_ts );
		$to_utc    = gmdate( 'Y-m-d H:i:s', $to_ts );
		$to_host   = ! empty( $config['reminder_host'] );

		$sent = 0;
		foreach ( $this->bookings->due_for_reminder( $from_utc, $to_utc ) as $booking ) {
			$host = $this->hosts->get( (int) $booking['host_id'] );
			$type = $this->types->get( (int) $booking['type_id'] );
			if ( null === $host || null === $type ) {
				continue;
			}
			$contact = ! empty( $booking['contact_id'] ) ? $this->contacts->get( (int) $booking['contact_id'] ) : null;
			$to      = null !== $contact ? sanitize_email( (string) ( $contact['email'] ?? '' ) ) : '';
			if ( '' === $to ) {
				continue;
			}

			if ( ! $this->mailer->send_reminder( $to, false, $booking, $host, $type, (array) $contact ) ) {
				// Kein erfolgreicher Versand -> Flag NICHT setzen, spaeterer Lauf holt nach.
				continue;
			}
			$this->bookings->mark_reminder_sent( (int) $booking['id'] );
			$sent++;

			if ( $to_host ) {
				$host_to = $this->mailer_host_email( $host );
				if ( '' !== $host_to ) {
					$this->mailer->send_reminder( $host_to, true, $booking, $host, $type, (array) $contact );
				}
			}
		}
		return $sent;
	}

	/**
	 * Einstellungen der Erinnerung. Seam.
	 *
	 * @return array{reminder_hours:int,reminder_host:bool}
	 */
	protected function config(): array {
		$settings = Core::instance()->settings( 'kurato' );
		return array(
			'reminder_hours' => (int) $settings->get( 'booking.reminder_hours', 24 ),
			'reminder_host'  => (bool) $settings->get( 'booking.reminder_host', true ),
		);
	}

	/**
	 * Host-Erinnerungsadresse: verknuepfter WP-Benutzer oder Administrator-Adresse.
	 *
	 * @param array<string, mixed> $host Host.
	 * @return string
	 */
	protected function mailer_host_email( array $host ): string {
		if ( ! empty( $host['user_id'] ) && function_exists( 'get_userdata' ) ) {
			$user = get_userdata( (int) $host['user_id'] );
			if ( $user && '' !== (string) $user->user_email ) {
				return sanitize_email( (string) $user->user_email );
			}
		}
		return sanitize_email( (string) get_option( 'admin_email', '' ) );
	}
}
