<?php

namespace WPEventGenius\Admin\Actions;

use WPEventGenius\Common\Database;
use WPEventGenius\Common\Utils\Utils;

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

class RegistrationRecord {

	protected $registration_id;

	protected $database;

	protected $raw_registration_data;

	protected $payment_data;

	public function __construct( Database $db, $registration_id ) {
		$this->database = $db;
		$this->registration_id = $registration_id;
		$query_data = $this->database->query_registration_record( $this->registration_id );
		$this->raw_registration_data = array();
		if ( ! empty( $query_data[0] ) ) {
			$this->raw_registration_data = Utils::hydrate_meta_cache( $query_data[0] );
		}

		$where = array(
			array(
				'column' => 'registration_id',
				'value' => $registration_id,
				'compare' => '=',
				'type' => 'int'
			)
		);
		$this->payment_data = $this->database->payment_query( $where );
	}

	public function get_registration_data() {
		if ( empty( $this->raw_registration_data ) ) {
			return array();
		}
		return $this->raw_registration_data;
	}

	public function get_payment_data() {
		if ( empty( $this->payment_data ) ) {
			return array();
		}
		return $this->payment_data[0];
	}

	public function get_registration_id() {
		return $this->registration_id;
	}

	/**
	 * Get the event ID for this registration
	 * 
	 * @return int|false The event ID or false if not found
	 */
	public function get_event_id() {
		if ( empty( $this->raw_registration_data ) || ! isset( $this->raw_registration_data['event_id'] ) ) {
			return false;
		}
		return (int) $this->raw_registration_data['event_id'];
	}

	public function delete() {
		// Get registration data before deletion for the action
		$registration_data = $this->get_registration_data();
		
		$this->database->delete_registration( $this->registration_id );
		
		/**
		 * Fires after a registration has been deleted
		 * 
		 * @param int $registration_id The deleted registration ID
		 * @param array $registration_data The registration data before deletion
		 */
		do_action( 'evge_registration_deleted', $this->registration_id, $registration_data );
	}

	public function create( $column_value, $form_fields ) {
		$insert_id = $this->database->insert_registration( $column_value, $form_fields );
		if ( empty( $insert_id ) ) {
			return false;
		}
		$this->registration_id = $insert_id;

		/**
		 * Fires after a registration has been created (admin).
		 *
		 * @param int   $insert_id    The new registration ID.
		 * @param array $column_value The data used for the insert (includes event_id).
		 */
		do_action( 'evge_registration_created', $insert_id, $column_value );

		return $insert_id;
	}

	public function update( $standard_data, $meta_data ) {
		// Get registration data before update for the action
		$old_registration_data = $this->get_registration_data();
		
		$this->database->update_registration( $this->registration_id, $standard_data, $meta_data );
		
		// Get updated registration data
		$query_data = $this->database->query_registration_record( $this->registration_id );
		$new_registration_data = array();
		if ( ! empty( $query_data[0] ) ) {
			$new_registration_data = \WPEventGenius\Common\Utils\Utils::hydrate_meta_cache( $query_data[0] );
		}
		
		/**
		 * Fires after a registration has been updated
		 * 
		 * @param int $registration_id The updated registration ID
		 * @param array $old_registration_data The registration data before update
		 * @param array $new_registration_data The registration data after update
		 */
		do_action( 'evge_registration_updated', $this->registration_id, $old_registration_data, $new_registration_data );
	}

	/**
	 * Get related registrations that share the same user ID or email address
	 *
	 * @return array Array of related registration records
	 */
	public function get_related_registrations() {
		if (empty($this->raw_registration_data)) {
			return [];
		}

		$related_registrations = [];
		
		// Get registrations by user ID if it exists
		if (!empty($this->raw_registration_data['user_id'])) {
			$user_where = [
				[
					'column' => 'user_id',
					'value' => $this->raw_registration_data['user_id'],
					'compare' => '=',
					'type' => 'int'
				]
			];
			$user_registrations = $this->database->registration_joined_query(
				$user_where,
				['payments'],
				'registration_date DESC'
			);
			if (!empty($user_registrations)) {
				$related_registrations = array_merge($related_registrations, $user_registrations);
			}
		}
		
		// Get registrations by email if it exists
		if (!empty($this->raw_registration_data['email'])) {
			$email_registrations = $this->database->search_registrations($this->raw_registration_data['email']);
			if (!empty($email_registrations)) {
				$related_registrations = array_merge($related_registrations, $email_registrations);
			}
		}
		
		// Remove duplicates and current registration
		$filtered_registrations = [];
		$seen_ids = [];
		foreach ($related_registrations as $registration) {
			$reg_id = $registration['id'];
			if ($reg_id != $this->registration_id && !isset($seen_ids[$reg_id])) {
				$seen_ids[$reg_id] = true;
				$filtered_registrations[] = Utils::hydrate_meta_cache($registration);
			}
		}
		
		return $filtered_registrations;
	}

	/**
	 * Get additional guest registrations for this registration
	 * If this is a guest registration, returns all related guests including the main registration
	 * If this is a main registration, returns all additional guests
	 *
	 * @return array Array of guest registration records with 'is_main' flag
	 */
	public function get_additional_guest_registrations() {
		if (empty($this->raw_registration_data)) {
			return [];
		}

		$parent_id = isset($this->raw_registration_data['parent']) ? (int) $this->raw_registration_data['parent'] : 0;
		$main_registration_id = $parent_id > 0 ? $parent_id : $this->registration_id;
		
		// Get all guest registrations for this group (including main)
		$where = [
			[
				'column' => 'parent',
				'value' => $main_registration_id,
				'compare' => '=',
				'type' => 'int'
			]
		];
		
		$guest_registrations = $this->database->registration_joined_query(
			$where,
			['payments'],
			'registration_date ASC'
		);

		// Add the main registration to the list
		$main_where = [
			[
				'column' => 'id',
				'value' => $main_registration_id,
				'compare' => '=',
				'type' => 'int'
			]
		];
		
		$main_registrations = $this->database->registration_joined_query(
			$main_where,
			['payments'],
			'registration_date ASC'
		);

		// Combine all registrations
		$all_registrations = array_merge($main_registrations, $guest_registrations);

		// Hydrate meta cache and add is_main flag
		$hydrated_guests = [];
		foreach ($all_registrations as $registration) {
			$hydrated_registration = Utils::hydrate_meta_cache($registration);
			$hydrated_registration['is_main'] = ($registration['id'] == $main_registration_id);
			$hydrated_guests[] = $hydrated_registration;
		}

		// Sort by registration date, with main registration first
		usort($hydrated_guests, function($a, $b) {
			if ($a['is_main'] && !$b['is_main']) return -1;
			if (!$a['is_main'] && $b['is_main']) return 1;
			return strtotime($a['registration_date']) - strtotime($b['registration_date']);
		});

		return $hydrated_guests;
	}

	/**
	 * Get registration type breakdown for display on the single registration view.
	 * For a main + additional guests group, uses each registration row's type (not payment_items aggregate).
	 * Otherwise uses payment_items for the group (main registration id); fallback to guest count or single type.
	 *
	 * @return array{ 'lines': array<int, array{ name: string, quantity: int, unit_price_display: string, line_total_display: string, registrant_label?: string }>, 'payment_completed': bool, 'per_registrant'?: bool }
	 */
	public function get_registration_type_breakdown() {
		$default = array(
			'lines'             => array(),
			'payment_completed' => false,
		);
		if ( empty( $this->raw_registration_data ) ) {
			return $default;
		}
		$data     = $this->raw_registration_data;
		$event_id = isset( $data['event_id'] ) ? (int) $data['event_id'] : 0;
		$parent   = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
		$main_id  = $parent > 0 ? $parent : (int) $data['id'];

		$payment_data = $this->get_payment_data();
		$default['payment_completed'] = ! empty( $payment_data['payment_status'] ) && $payment_data['payment_status'] === 'completed';

		$group_members = $this->get_additional_guest_registrations();
		if ( count( $group_members ) > 1 ) {
			$lines         = array();
			$guest_counter = 0;
			foreach ( $group_members as $g ) {
				$type_id = isset( $g['event_registration_type_id'] ) ? (int) $g['event_registration_type_id'] : 0;
				$name    = __( 'General', 'event-genius' );
				if ( $type_id > 0 ) {
					$type_row = $this->database->get_event_registration_type( $type_id );
					if ( $type_row && isset( $type_row['name'] ) && trim( (string) $type_row['name'] ) !== '' ) {
						$name = sanitize_text_field( (string) $type_row['name'] );
					}
				}
				if ( ! empty( $g['is_main'] ) ) {
					$registrant_label = __( 'Main registration', 'event-genius' );
				} else {
					++$guest_counter;
					$registrant_label = sprintf(
						/* translators: %d: additional guest number within the group (1, 2, 3, …). */
						__( 'Guest %d', 'event-genius' ),
						$guest_counter
					);
				}
				$lines[] = array(
					'name'               => $name,
					'quantity'           => 1,
					'unit_price_display' => '',
					'line_total_display' => '',
					'registrant_label'   => $registrant_label,
				);
			}
			if ( ! empty( $lines ) ) {
				$default['lines']          = $lines;
				$default['per_registrant'] = true;
				return $default;
			}
		}

		// 1) Prefer payment_items for main registration (single registrant or no per-row guest data).
		if ( $main_id > 0 ) {
			$items = $this->database->get_payment_items_by_registration_id( $main_id, false );
			if ( ! empty( $items ) ) {
				$lines = array();
				foreach ( $items as $item ) {
					$type_id = isset( $item['event_registration_type_id'] ) ? (int) $item['event_registration_type_id'] : 0;
					$qty     = isset( $item['quantity'] ) ? max( 0, (int) $item['quantity'] ) : 0;
					if ( $qty <= 0 ) {
						continue;
					}
					$name = isset( $item['registration_type_name_snapshot'] ) && trim( (string) $item['registration_type_name_snapshot'] ) !== ''
						? trim( (string) $item['registration_type_name_snapshot'] )
						: '';
					if ( $type_id > 0 ) {
						$type_row = $this->database->get_event_registration_type( $type_id );
						if ( $type_row && isset( $type_row['name'] ) && $name === '' ) {
							$name = sanitize_text_field( trim( (string) $type_row['name'] ) );
						}
					}
					if ( $name === '' ) {
						$name = __( 'General', 'event-genius' );
					}
					$unit_cents  = isset( $item['unit_price_amount_snapshot'] ) ? (int) $item['unit_price_amount_snapshot'] : 0;
					$total_cents = isset( $item['line_total_amount_snapshot'] ) ? (int) $item['line_total_amount_snapshot'] : 0;
					$lines[]     = array(
						'name'                => $name,
						'quantity'            => $qty,
						'unit_price_display'  => $unit_cents > 0 ? number_format_i18n( $unit_cents / 100, 2 ) : '',
						'line_total_display'  => $total_cents > 0 ? number_format_i18n( $total_cents / 100, 2 ) : '',
					);
				}
				if ( ! empty( $lines ) ) {
					$default['lines'] = $lines;
					return $default;
				}
			}
		}

		// 2) Fallback: derive from additional guest registrations (count by type).
		$guests = $this->get_additional_guest_registrations();
		if ( ! empty( $guests ) ) {
			$by_type = array();
			foreach ( $guests as $g ) {
				$type_id = isset( $g['event_registration_type_id'] ) ? (int) $g['event_registration_type_id'] : 0;
				if ( $type_id <= 0 ) {
					continue;
				}
				$by_type[ $type_id ] = isset( $by_type[ $type_id ] ) ? $by_type[ $type_id ] + 1 : 1;
			}
			if ( ! empty( $by_type ) ) {
				$type_ids = array_keys( $by_type );
				$names   = $this->database->get_event_registration_type_ids_to_names( $type_ids );
				$lines   = array();
				foreach ( $by_type as $type_id => $qty ) {
					$name = isset( $names[ $type_id ] ) && $names[ $type_id ] !== '' ? $names[ $type_id ] : __( 'General', 'event-genius' );
					$lines[] = array( 'name' => $name, 'quantity' => $qty, 'unit_price_display' => '', 'line_total_display' => '' );
				}
				$default['lines'] = $lines;
				return $default;
			}
		}

		// 3) Single type from main registration row.
		$type_id = isset( $data['event_registration_type_id'] ) ? (int) $data['event_registration_type_id'] : 0;
		$name    = __( 'General', 'event-genius' );
		if ( $type_id > 0 ) {
			$type_row = $this->database->get_event_registration_type( $type_id );
			if ( $type_row && isset( $type_row['name'] ) && trim( (string) $type_row['name'] ) !== '' ) {
				$name = sanitize_text_field( (string) $type_row['name'] );
			}
		}
		$qty = isset( $data['quantity'] ) ? max( 1, (int) $data['quantity'] ) : 1;
		$default['lines'] = array( array( 'name' => $name, 'quantity' => $qty, 'unit_price_display' => '', 'line_total_display' => '' ) );
		return $default;
	}

	/**
	 * Type id to preselect in the admin edit form (matches breakdown / summary where possible).
	 * Guests use their row; main registration prefers payment_items (same iteration as get_registration_type_breakdown), then main guest row, then DB column.
	 *
	 * @return int
	 */
	public function get_preferred_event_registration_type_id_for_edit_form() {
		if ( empty( $this->raw_registration_data ) ) {
			return 0;
		}
		$data     = $this->raw_registration_data;
		$parent   = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
		$row_type = isset( $data['event_registration_type_id'] ) ? (int) $data['event_registration_type_id'] : 0;

		if ( $parent > 0 ) {
			return $row_type;
		}

		$main_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
		if ( $main_id <= 0 ) {
			return $row_type;
		}

		$items = $this->database->get_payment_items_by_registration_id( $main_id, false );
		if ( ! empty( $items ) && is_array( $items ) ) {
			$types_seen = array();
			$first_type = 0;
			foreach ( $items as $item ) {
				$type_id = isset( $item['event_registration_type_id'] ) ? (int) $item['event_registration_type_id'] : 0;
				$qty     = isset( $item['quantity'] ) ? max( 0, (int) $item['quantity'] ) : 0;
				if ( $type_id <= 0 || $qty <= 0 ) {
					continue;
				}
				if ( $first_type === 0 ) {
					$first_type = $type_id;
				}
				$types_seen[ $type_id ] = true;
			}
			$distinct = array_keys( $types_seen );
			if ( count( $distinct ) === 1 ) {
				return (int) $distinct[0];
			}
			if ( count( $distinct ) > 1 ) {
				if ( $row_type > 0 && isset( $types_seen[ $row_type ] ) ) {
					return $row_type;
				}
				return $first_type > 0 ? $first_type : $row_type;
			}
		}

		$guests = $this->get_additional_guest_registrations();
		if ( ! empty( $guests ) ) {
			foreach ( $guests as $g ) {
				if ( ! empty( $g['is_main'] ) ) {
					$tid = isset( $g['event_registration_type_id'] ) ? (int) $g['event_registration_type_id'] : 0;
					if ( $tid > 0 ) {
						return $tid;
					}
					break;
				}
			}
		}

		return $row_type;
	}
}