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

namespace Hafenstudios\Leadlotse;

use Hafenstudios\Core\Core;
use Hafenstudios\Core\Support\SelfUpdater;
use Hafenstudios\Leadlotse\Admin\BuilderPage;
use Hafenstudios\Leadlotse\Admin\FormsListPage;
use Hafenstudios\Leadlotse\Admin\IdentityPage;
use Hafenstudios\Leadlotse\Admin\InboxPage;
use Hafenstudios\Leadlotse\Admin\MailSenderPage;
use Hafenstudios\Leadlotse\Admin\Menu;
use Hafenstudios\Leadlotse\Admin\ParticipantsPage;
use Hafenstudios\Leadlotse\Admin\SetupChecklist;
use Hafenstudios\Leadlotse\Db\EntryRepository;
use Hafenstudios\Leadlotse\Doi\DoiService;
use Hafenstudios\Leadlotse\Events\EventCapacity;
use Hafenstudios\Leadlotse\Events\TicketMailer;
use Hafenstudios\Leadlotse\Events\TicketPage;
use Hafenstudios\Leadlotse\Events\TicketToken;
use Hafenstudios\Leadlotse\Frontend\FormRenderer;
use Hafenstudios\Leadlotse\Frontend\Frontend;
use Hafenstudios\Leadlotse\Fields\ConditionalLogic;
use Hafenstudios\Leadlotse\Fields\FieldRegistry;
use Hafenstudios\Leadlotse\Forms\DefinitionSchema;
use Hafenstudios\Leadlotse\Forms\FormPostType;
use Hafenstudios\Leadlotse\Identity\IdentityService;
use Hafenstudios\Leadlotse\Install\Installer;
use Hafenstudios\Leadlotse\Privacy\PrivacyBridge;
use Hafenstudios\Leadlotse\Rest\EntriesController;
use Hafenstudios\Leadlotse\Rest\FormsController;
use Hafenstudios\Leadlotse\Rest\IdentityController;
use Hafenstudios\Leadlotse\Rest\PublicController;
use Hafenstudios\Leadlotse\Submit\FallbackHandler;
use Hafenstudios\Leadlotse\Submit\MailService;
use Hafenstudios\Leadlotse\Submit\SpamGuard;
use Hafenstudios\Leadlotse\Submit\SubmitHandler;

defined( 'ABSPATH' ) || exit;

/**
 * Zentrale Verdrahtung von Leadlotse (Etappe 2: Backend-Fundament).
 *
 * Registriert CPT, REST-API, No-JS-Fallback, Privacy-Anbindung und den
 * Wartungs-Cron und stellt die gemeinsam genutzten Dienste als schlanke
 * Registry bereit. Admin-UI (Builder, Inbox) und Frontend-Rendering folgen
 * in Etappe 3/4 und docken hier an.
 */
final class Plugin {

	private static ?Plugin $instance = null;

	/**
	 * @var array<string, object>
	 */
	private array $services = array();

	private bool $booted = false;

	private function __construct() {}

	public static function instance(): Plugin {
		return self::$instance ??= new self();
	}

	/**
	 * Verdrahtet alle Bestandteile. Idempotent.
	 *
	 * @return void
	 */
	public function boot(): void {
		if ( $this->booted ) {
			return;
		}
		$this->booted = true;

		add_action( 'init', array( $this, 'on_init' ) );

		// Core kennt Leadlotse (fuer Kompass/geteilte Ansichten).
		Core::instance()->register_plugin(
			'leadlotse',
			array(
				'name'      => __( 'Leadlotse', 'leadlotse' ),
				'version'   => LEADLOTSE_VERSION,
				'menu_slug' => 'leadlotse',
			)
		);

		// Hans-Motive: Basis-URL aus der gebuendelten Core-Kopie bereitstellen.
		add_filter(
			'hafenstudios/hans_image_base_url',
			static function ( $url ) {
				if ( '' !== (string) $url || ! defined( 'HAFENSTUDIOS_CORE_DIR' ) ) {
					return $url;
				}
				$dir         = wp_normalize_path( HAFENSTUDIOS_CORE_DIR . '/assets/img/hans' );
				$content_dir = wp_normalize_path( WP_CONTENT_DIR );
				if ( 0 === strpos( $dir, $content_dir ) ) {
					return trailingslashit( content_url( substr( $dir, strlen( $content_dir ) ) ) );
				}
				return $url;
			}
		);

		// Selbst-Update gegen das statische Manifest auf hafenstudios.com
		// (Muster Wellenbrecher WB12, seit dem Pro-Launch im Core). Host-gebunden
		// und fail-silent; der WP-Kern feuert den Filter anhand des
		// "Update URI"-Headers. Ohne das haetten zahlende Kunden keinen
		// Update-Pfad - Freemius liefert in der Ein-Paket-Architektur keine ZIPs.
		( new SelfUpdater(
			'leadlotse',
			plugin_basename( LEADLOTSE_FILE ),
			defined( 'LEADLOTSE_VERSION' ) ? LEADLOTSE_VERSION : '1.0.0'
		) )->register();

		// REST-API leadlotse/v1 (D8: alle Datenoperationen laufen hierueber).
		add_action(
			'rest_api_init',
			function () {
				( new FormsController( $this->definition_schema() ) )->register_routes();
				( new EntriesController( $this->entries() ) )->register_routes();
				( new PublicController( $this->submit_handler(), $this->doi() ) )->register_routes();
				( new IdentityController( $this->identity() ) )->register_routes();
			}
		);

		// Klassischer POST-Fallback ohne JS (D8).
		( new FallbackHandler( $this->submit_handler() ) )->register();

		// Designierter Restore-Weg (W-L1 c): erlaubt einem Admin-Kontext mit
		// Capability (Wellenbrechers Quarantaene-Seite), einen abgefangenen
		// Payload mit Spam-Bypass erneut durch die Pipeline zu schicken. Kein
		// oeffentlicher Endpoint - die restore()-Methode prueft die Cap selbst.
		add_filter( 'hafenstudios/leadlotse_restore_submit', array( $this->submit_handler(), 'restore' ), 10, 4 );

		// Frontend (Etappe 3): Shortcode, Gutenberg-Block, Renderer-Assets.
		$this->frontend()->register();

		// Veranstaltungs-Tickets (L-R1): Ticket-Mail nach Bestaetigung,
		// oeffentliche Ticket-/Check-in-Seiten, CSV-Export der Teilnehmer.
		$tokens = new TicketToken();
		( new TicketMailer( $this->entries(), $tokens ) )->register();
		( new TicketPage( $this->entries(), $tokens ) )->register();
		$participants_page = new ParticipantsPage( $this->entries() );
		$participants_page->register();

		// Admin-Menue: Formularliste (Etappe 3), Inbox, Builder (Etappe 4),
		// Onboarding-Checkliste und Hans-Hinweise (Etappe 5).
		if ( is_admin() ) {
			$forms_page    = new FormsListPage( $this->entries(), new SetupChecklist( $this->entries() ) );
			$identity_page = new IdentityPage();
			$identity_page->register();
			$mail_page = new MailSenderPage();
			$mail_page->register();
			( new Menu( $forms_page, new InboxPage( $this->entries(), $participants_page ), new BuilderPage(), $identity_page, $mail_page ) )->register();
		}

		// Privacy: Entries an WP-Export/-Loeschung anbinden.
		( new PrivacyBridge( $this->entries() ) )->register();

		// Taegliche Wartung: abgelaufene DOI-Anmeldungen und Aufbewahrungsfrist.
		add_action( Installer::CRON_HOOK, array( $this, 'run_maintenance' ) );

		// Nach Plugin-Updates ausstehende Migrationen nachziehen.
		add_action(
			'admin_init',
			static function () {
				Installer::migrate();
			}
		);
	}

	/**
	 * init-Hook: Textdomain und CPT.
	 *
	 * @return void
	 */
	public function on_init(): void {
		load_plugin_textdomain( 'leadlotse', false, dirname( plugin_basename( LEADLOTSE_FILE ) ) . '/languages' );
		( new FormPostType() )->register();
	}

	/**
	 * Taegliche Wartung.
	 *
	 * @return void
	 */
	public function run_maintenance(): void {
		$settings = $this->settings();

		// Unbestaetigte DOI-Anmeldungen nach doppelter Token-Laufzeit entfernen.
		$expiry_hours = absint( $settings->get( 'doi.expiry_hours', 48 ) );
		$this->entries()->delete_expired_doi( max( 7, (int) ceil( ( $expiry_hours * 2 ) / 24 ) ) );

		// Konfigurierbare Aufbewahrungsfrist (0 = aus).
		$this->entries()->delete_older_than_months( absint( $settings->get( 'privacy.retention_months', 0 ) ) );
	}

	/**
	 * Settings-Speicher (Core-Framework, Namespace leadlotse).
	 *
	 * @return \Hafenstudios\Core\Settings\Settings
	 */
	public function settings() {
		return Core::instance()->settings( 'leadlotse', Installer::default_settings() );
	}

	/**
	 * Entry-Repository.
	 *
	 * @return EntryRepository
	 */
	public function entries(): EntryRepository {
		return $this->services['entries'] ??= new EntryRepository();
	}

	/**
	 * Feldtyp-Registry.
	 *
	 * @return FieldRegistry
	 */
	public function fields(): FieldRegistry {
		return $this->services['fields'] ??= new FieldRegistry();
	}

	/**
	 * Conditional-Logic-Service.
	 *
	 * @return ConditionalLogic
	 */
	public function conditions(): ConditionalLogic {
		return $this->services['conditions'] ??= new ConditionalLogic();
	}

	/**
	 * Definitions-Schema (Formular-Validierung).
	 *
	 * @return DefinitionSchema
	 */
	public function definition_schema(): DefinitionSchema {
		return $this->services['schema'] ??= new DefinitionSchema( $this->fields(), $this->conditions() );
	}

	/**
	 * DOI-Service (D9).
	 *
	 * @return DoiService
	 */
	public function doi(): DoiService {
		return $this->services['doi'] ??= new DoiService( $this->entries() );
	}

	/**
	 * Mail-Service (Bestaetigung, Benachrichtigung, DOI).
	 *
	 * @return MailService
	 */
	public function mails(): MailService {
		return $this->services['mails'] ??= new MailService();
	}

	/**
	 * Frontend-Renderer (Block, Shortcode und Builder-Vorschau, Etappe 3).
	 *
	 * @return FormRenderer
	 */
	public function renderer(): FormRenderer {
		return $this->services['renderer'] ??= new FormRenderer(
			$this->fields(),
			$this->conditions(),
			new SpamGuard(),
			$this->identity(),
			new EventCapacity( $this->entries() )
		);
	}

	/**
	 * Ausfuellhilfe-Dienst (Weiter mit Google/Apple, ohne WP-Login).
	 *
	 * @return IdentityService
	 */
	public function identity(): IdentityService {
		return $this->services['identity'] ??= new IdentityService( $this->settings() );
	}

	/**
	 * Frontend-Verdrahtung (Shortcode, Block, Assets, Etappe 3).
	 *
	 * @return Frontend
	 */
	public function frontend(): Frontend {
		return $this->services['frontend'] ??= new Frontend( $this->renderer() );
	}

	/**
	 * Submit-Pipeline (REST und Fallback nutzen dieselbe Instanz).
	 *
	 * @return SubmitHandler
	 */
	public function submit_handler(): SubmitHandler {
		return $this->services['submit'] ??= new SubmitHandler(
			$this->fields(),
			$this->conditions(),
			new SpamGuard(),
			$this->entries(),
			$this->doi(),
			$this->mails(),
			$this->identity()
		);
	}
}
