<?php
/**
 * Basic registration type: no dynamic types. Always a pseudo type built from event details
 * (event title as label, event cost as unit price). Used in Free/Basic when the registration
 * types table is not used; Standard+ uses RegistrationTypeStandard and the types table.
 *
 * @since 2.21
 */
namespace WPEventGenius\Common\Registration;

use WPEventGenius\Common\Database;

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

class RegistrationType {

	/**
	 * @var Database
	 */
	protected $database;

	/**
	 * @var int|null Registration type ID (evge_event_registration_types.id).
	 */
	protected $id = null;

	/**
	 * @var int Event post ID.
	 */
	protected $event_id = 0;

	/**
	 * Snapshot data for payment_items; only refreshed when ID changes.
	 *
	 * @var int|null
	 */
	protected $template_id_snapshot = null;

	/**
	 * @var string
	 */
	protected $name_snapshot = '';

	/**
	 * @var float Unit price in dollars (computed at load).
	 */
	protected $unit_price_dollars = 0.0;

	/**
	 * @param Database|null $database
	 */
	public function __construct( ?Database $database = null ) {
		$this->database = $database ? $database : new Database();
	}

	/**
	 * Build from a registration type ID (and event ID for validation and price).
	 * Uses RegistrationObjectFactory so the correct implementation (basic or Standard+) is returned.
	 *
	 * @param int           $type_id  evge_event_registration_types.id.
	 * @param int           $event_id Event post ID.
	 * @param Database|null $database Optional.
	 * @return self|RegistrationType
	 */
	public static function from_id( $type_id, $event_id, ?Database $database = null ) {
		$factory = new \WPEventGenius\Common\Services\RegistrationObjectFactory();
		return $factory->create_registration_type( $type_id, $event_id, $database );
	}

	/**
	 * Set the type by ID. Basic version ignores type_id and always builds a pseudo type from event.
	 *
	 * @param int $type_id  Ignored in Basic; event default only.
	 * @param int $event_id Event post ID.
	 */
	public function set_type_id( $type_id, $event_id ) {
		$event_id = (int) $event_id;
		if ( $event_id === (int) $this->event_id && $this->name_snapshot !== '' ) {
			return;
		}
		$this->id       = null;
		$this->event_id = $event_id;
		if ( $event_id > 0 ) {
			$this->load_from_event( $event_id );
		}
	}

	/**
	 * Build a pseudo type from event details only (no registration types table).
	 * Label = event title, unit price = event cost. Subclasses (Standard+) use the types table instead.
	 *
	 * @param int $event_id Event post ID.
	 */
	protected function load_from_event( $event_id ) {
		$event_id = (int) $event_id;
		if ( $event_id <= 0 ) {
			return;
		}
		$this->id                   = null;
		$this->event_id             = $event_id;
		$this->template_id_snapshot = null;
		$this->name_snapshot        = get_the_title( $event_id ) ?: '';
		$cost                       = get_post_meta( $event_id, 'evge_cost_amount', true );
		$this->unit_price_dollars   = is_numeric( $cost ) && (float) $cost >= 0 ? (float) $cost : 0.0;
	}

	/**
	 * Load type row from DB and set snapshot data (used by Standard+ only).
	 * Subclasses override populate_extra_from_row() to set tier-specific fields from the same row.
	 *
	 * @param int $type_id
	 * @param int $event_id
	 */
	protected function load_from_id( $type_id, $event_id ) {
		$row = $this->database->get_event_registration_type( $type_id );
		if ( ! $row || ! is_array( $row ) || (int) $row['event_id'] !== $event_id ) {
			return;
		}
		$this->set_from_row( $row, $event_id );
		$this->populate_extra_from_row( $row );
	}

	/**
	 * Set basic snapshot data from a type row (id, name, price, etc.).
	 *
	 * @param array<string, mixed> $row     Type row from get_event_registration_type.
	 * @param int                  $event_id Event post ID.
	 */
	protected function set_from_row( array $row, $event_id ) {
		$this->id                   = (int) $row['id'];
		$this->event_id             = (int) $row['event_id'];
		$this->template_id_snapshot = isset( $row['template_id'] ) && $row['template_id'] !== null && $row['template_id'] !== ''
			? (int) $row['template_id']
			: null;
		$this->name_snapshot        = isset( $row['name'] ) ? sanitize_text_field( (string) $row['name'] ) : '';
		$this->unit_price_dollars   = $this->compute_unit_price_dollars( $event_id, $row );
	}

	/**
	 * Override in subclasses to set tier-specific fields from the same type row (e.g. capacity, status).
	 * Called once after set_from_row() so only one DB query is needed.
	 *
	 * @param array<string, mixed> $row Type row from get_event_registration_type.
	 */
	protected function populate_extra_from_row( array $row ) {
		// Basic version: no extra fields.
	}

	/**
	 * Effective unit price in dollars (event cost when use_event_price, else type price).
	 *
	 * @param int   $event_id
	 * @param array $type_row
	 * @return float
	 */
	protected function compute_unit_price_dollars( $event_id, array $type_row ) {
		$use_event = ! empty( $type_row['use_event_price'] );
		if ( $use_event && $event_id > 0 ) {
			$cost = get_post_meta( (int) $event_id, 'evge_cost_amount', true );
			return is_numeric( $cost ) && (float) $cost >= 0 ? (float) $cost : 0.0;
		}
		$cents = isset( $type_row['price_amount'] ) ? (int) $type_row['price_amount'] : 0;
		if ( $cents >= 100 || $cents === 0 ) {
			return (float) ( $cents / 100 );
		}
		return (float) $cents;
	}

	/**
	 * Registration type ID for evge_registrations.event_registration_type_id.
	 *
	 * @return int|null
	 */
	public function get_registration_type_id() {
		return $this->id;
	}

	/**
	 * Alias for get_registration_type_id().
	 *
	 * @return int|null
	 */
	public function get_id() {
		return $this->id;
	}

	/**
	 * @return int
	 */
	public function get_event_id() {
		return (int) $this->event_id;
	}

	/**
	 * Label for display / payment_items (type name).
	 *
	 * @return string
	 */
	public function get_label() {
		return $this->name_snapshot;
	}

	/**
	 * Unit price in dollars.
	 *
	 * @return float
	 */
	public function get_unit_price_dollars() {
		return $this->unit_price_dollars;
	}

	/**
	 * Meta for cart LineItem (event_registration_type_id, template_id, name).
	 *
	 * @return array<string, mixed>
	 */
	public function get_payment_item_meta() {
		return array(
			'event_registration_type_id' => $this->id,
			'template_id'                => $this->template_id_snapshot,
			'name'                      => $this->name_snapshot,
		);
	}

	/**
	 * Data for one payment_items row (excluding payment_id; callers add it).
	 * Use when creating evge_payment_items from this type.
	 *
	 * @param int    $event_id  Event post ID.
	 * @param int    $quantity  Quantity for this line.
	 * @param string $currency  Currency code (e.g. USD).
	 * @return array<string, mixed> Keys: event_id, label, line_item_kind, currency_snapshot, unit_price_amount_snapshot, quantity, line_total_amount_snapshot, event_registration_type_id, registration_type_template_id_snapshot, registration_type_name_snapshot.
	 */
	public function get_payment_item_row( $event_id, $quantity = 1, $currency = 'USD' ) {
		$quantity   = max( 1, (int) $quantity );
		$unit_cents = (int) round( $this->unit_price_dollars * 100 );
		$total_cents = (int) round( $this->unit_price_dollars * $quantity * 100 );
		return array(
			'event_id'                               => (int) $event_id,
			'label'                                  => $this->name_snapshot ? substr( sanitize_text_field( $this->name_snapshot ), 0, 255 ) : '',
			'line_item_kind'                         => 'registration_type',
			'currency_snapshot'                      => substr( sanitize_text_field( $currency ), 0, 3 ),
			'unit_price_amount_snapshot'            => $unit_cents,
			'quantity'                               => $quantity,
			'line_total_amount_snapshot'            => $total_cents,
			'event_registration_type_id'            => $this->id,
			'registration_type_template_id_snapshot' => $this->template_id_snapshot,
			'registration_type_name_snapshot'       => $this->name_snapshot ? substr( $this->name_snapshot, 0, 255 ) : null,
		);
	}

	/**
	 * Whether this instance has a valid type (real type from DB or event pseudo type).
	 *
	 * @return bool
	 */
	public function has_type() {
		return ( $this->id !== null && $this->id > 0 ) || $this->event_id > 0;
	}
}
