<?php
/**
 * Single producer for "line items" — everything we charge for in one payment or bulk order.
 * Used for both potential line items (display / dynamic pricing) and actual line items (Cart at submit).
 *
 * Potential line items use {@see LineItem} (display / JSON). Cart line items for a group are keyed LineItem instances.
 *
 * @package WPEventGenius
 */

namespace WPEventGenius\Common\Services;

use WPEventGenius\Common\Database;
use WPEventGenius\Common\Event\Event;
use WPEventGenius\Common\Event\EventPost;
use WPEventGenius\Common\Registration\Payment\Cart\LineItem;
use WPEventGenius\Common\Registration\Registration\RegistrationGroup;
use WPEventGenius\Common\Registration\RegistrationType;

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

class LineItemsService {

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

	/**
	 * @var PaymentItemsService
	 */
	protected $payment_items_service;

	public function __construct( ?Database $database = null, ?PaymentItemsService $payment_items_service = null ) {
		$this->database             = $database ? $database : new Database();
		$this->payment_items_service = $payment_items_service ? $payment_items_service : new PaymentItemsService( $this->database );
	}

	/**
	 * Potential line items for display / dynamic price summary (pre-payment).
	 * Given event and current or initial form state, returns the same line-item shape we use for the cart.
	 *
	 * @param EventPost $event_post        Event (or event-like) post.
	 * @param array     $registration_data Optional. May contain:
	 *   - initial_type_quantities: array type_id => quantity
	 *   - registration_types: array of { type_id, quantity } (e.g. from form state)
	 * @return LineItem[] Indexed list of potential line items (for summaries before payment).
	 */
	public function get_potential_line_items( EventPost $event_post, array $registration_data = [] ) {
		$initial_type_quantities = isset( $registration_data['initial_type_quantities'] ) && is_array( $registration_data['initial_type_quantities'] )
			? $registration_data['initial_type_quantities']
			: array();
		$registration_types      = isset( $registration_data['registration_types'] ) && is_array( $registration_data['registration_types'] )
			? $registration_data['registration_types']
			: array();

		$use_type_based = method_exists( $event_post, 'use_type_based_costs' ) && $event_post->use_type_based_costs();
		if ( ! $use_type_based ) {
			$quantity   = 1;
			$event_cost = method_exists( $event_post, 'get_the_cost_amount' ) ? (float) $event_post->get_the_cost_amount() : 0.0;
			if ( ! empty( $initial_type_quantities ) ) {
				$quantity = max( 1, (int) array_sum( $initial_type_quantities ) );
			} elseif ( ! empty( $registration_types ) ) {
				$qty_sum = 0;
				foreach ( $registration_types as $row ) {
					if ( is_array( $row ) && isset( $row['quantity'] ) ) {
						$qty_sum += max( 0, (int) $row['quantity'] );
					}
				}
				$quantity = $qty_sum > 0 ? $qty_sum : 1;
			}
			$title = method_exists( $event_post, 'get_the_title' ) ? $event_post->get_the_title() : '';
			$line_total = round( $quantity * $event_cost, 2 );
			return array(
				new LineItem(
					$title,
					$quantity,
					$event_cost,
					array(
						'line_total' => $line_total,
					)
				),
			);
		}

		$types_for_display = method_exists( $event_post, 'get_types_for_payment_display' ) ? $event_post->get_types_for_payment_display() : array();
		if ( empty( $types_for_display ) ) {
			$title = method_exists( $event_post, 'get_the_title' ) ? $event_post->get_the_title() : '';
			$cost  = method_exists( $event_post, 'get_the_cost_amount' ) ? (float) $event_post->get_the_cost_amount() : 0.0;
			return array(
				new LineItem(
					$title,
					1,
					$cost,
					array(
						'line_total' => $cost,
					)
				),
			);
		}

		$title = method_exists( $event_post, 'get_the_title' ) ? $event_post->get_the_title() : '';
		$lines = array();
		foreach ( $types_for_display as $type_row ) {
			$type_id   = isset( $type_row['id'] ) ? (int) $type_row['id'] : 0;
			$type_name = isset( $type_row['name'] ) ? $type_row['name'] : '';
			$price     = isset( $type_row['price'] ) ? (float) $type_row['price'] : 0.0;
			$qty       = isset( $initial_type_quantities[ $type_id ] ) ? (int) $initial_type_quantities[ $type_id ] : 0;
			foreach ( $registration_types as $row ) {
				if ( is_array( $row ) && isset( $row['type_id'] ) && (int) $row['type_id'] === $type_id && isset( $row['quantity'] ) ) {
					$qty = max( 0, (int) $row['quantity'] );
					break;
				}
			}
			$line_total = round( $qty * $price, 2 );
			$meta       = array(
				'line_total' => $line_total,
			);
			if ( $type_id > 0 ) {
				$meta['type_id'] = $type_id;
			}
			$lines[] = new LineItem(
				$title . ( $type_name !== '' ? ' – ' . $type_name : '' ),
				$qty,
				$price,
				$meta
			);
		}
		return $lines;
	}

	/**
	 * Line items for a registration group (actual cart at submit or when loading from DB).
	 * Keyed by line-item slug; values are {@see LineItem} (same as Cart).
	 *
	 * @param RegistrationGroup $group
	 * @return array<string, LineItem>
	 */
	public function get_line_items_for_group( RegistrationGroup $group ) {
		$main = $group->get_main();
		if ( ! $main ) {
			return array();
		}
		$event_id = (int) $main->get_registration_data( 'event_id' );
		if ( $event_id <= 0 ) {
			return array();
		}
		$event = new Event( $event_id );

		$line_items = $this->build_line_items_from_registration_types( $group, $event_id, $event );
		return $line_items;
	}

	/**
	 * Build keyed line items from group's registration types or payment_items or single type + guests.
	 *
	 * @param RegistrationGroup $group
	 * @param int               $event_id
	 * @param Event             $event
	 * @return array<string, LineItem>
	 */
	protected function build_line_items_from_registration_types( RegistrationGroup $group, $event_id, Event $event ) {
		$line_items = array();
		$main       = $group->get_main();

		$main_types = $main ? $main->get_registration_data( 'registration_types' ) : null;
		if ( is_array( $main_types ) && ! empty( $main_types ) ) {
			$main_index   = 0;
			$main_entry_id = $main ? (int) $main->get_entry_id() : 0;
			foreach ( $main_types as $row ) {
				if ( ! is_array( $row ) ) {
					continue;
				}
				$type_id  = isset( $row['type_id'] ) ? (int) $row['type_id'] : 0;
				$quantity = isset( $row['quantity'] ) ? max( 0, (int) $row['quantity'] ) : 0;
				if ( $type_id <= 0 || $quantity <= 0 ) {
					continue;
				}
				$main_index++;
				$reg_type = RegistrationType::from_id( $type_id, $event_id, $this->database );
				if ( ! $reg_type->has_type() ) {
					continue;
				}
				$meta = array_merge(
					array(
						'label'           => $reg_type->get_label(),
						'quantity'        => $quantity,
						'cost'            => $reg_type->get_unit_price_dollars(),
						'registration_id' => $main_entry_id,
					),
					$reg_type->get_payment_item_meta()
				);
				$line_items[ 'registration_main_' . $main_index ] = new LineItem(
					$meta['label'],
					$meta['quantity'],
					$meta['cost'],
					$meta
				);
			}
		}

		if ( empty( $line_items ) && $main ) {
			$main_entry_id = (int) $main->get_entry_id();
			if ( $main_entry_id > 0 ) {
				$items = $this->database->get_payment_items_by_registration_id( $main_entry_id, false );
				if ( ! empty( $items ) && is_array( $items ) ) {
					$idx = 0;
					foreach ( $items as $row ) {
						if ( isset( $row['event_id'] ) && (int) $row['event_id'] !== $event_id ) {
							continue;
						}
						$qty = isset( $row['quantity'] ) ? max( 0, (int) $row['quantity'] ) : 0;
						if ( $qty <= 0 ) {
							continue;
						}
						$idx++;
						$label       = isset( $row['label'] ) ? $row['label'] : '';
						$unit_cents  = isset( $row['unit_price_amount_snapshot'] ) ? (int) $row['unit_price_amount_snapshot'] : 0;
						$cost        = $unit_cents / 100.0;
						$type_id     = isset( $row['event_registration_type_id'] ) ? (int) $row['event_registration_type_id'] : null;
						$template_id = isset( $row['registration_type_template_id_snapshot'] ) ? (int) $row['registration_type_template_id_snapshot'] : null;
						$name        = isset( $row['registration_type_name_snapshot'] ) ? $row['registration_type_name_snapshot'] : null;
						$row_meta = array_merge(
							array( 'label' => $label, 'quantity' => $qty, 'cost' => $cost, 'registration_id' => $main_entry_id ),
							array(
								'event_registration_type_id' => $type_id,
								'template_id'                => $template_id,
								'name'                      => $name,
							)
						);
						$line_items[ 'registration_main_' . $idx ] = new LineItem( $label, $qty, $cost, $row_meta );
					}
				}
			}
		}

		if ( empty( $line_items ) && $main ) {
			$reg_type = method_exists( $main, 'get_registration_type' ) ? $main->get_registration_type() : null;
			if ( $reg_type && $reg_type->has_type() ) {
				$qty  = (int) $main->get_registration_data( 'quantity' );
				$qty  = $qty > 0 ? $qty : 1;
				$meta = array_merge(
					array(
						'label'           => $reg_type->get_label(),
						'quantity'        => $qty,
						'cost'            => $reg_type->get_unit_price_dollars(),
						'registration_id' => (int) $main->get_entry_id(),
					),
					$reg_type->get_payment_item_meta()
				);
				$line_items['registration_main'] = new LineItem(
					$meta['label'],
					$meta['quantity'],
					$meta['cost'],
					$meta
				);
			}
		}

		foreach ( $group->get_additional_guest_registrations() as $guest_number => $guest_registration ) {
			$guest_type = method_exists( $guest_registration, 'get_registration_type' ) ? $guest_registration->get_registration_type() : null;
			if ( ! $guest_type || ! $guest_type->has_type() ) {
				continue;
			}
			$qty  = (int) $guest_registration->get_registration_data( 'quantity' );
			$qty  = $qty > 0 ? $qty : 1;
			$meta = array_merge(
				array(
					'label'           => $guest_type->get_label(),
					'quantity'        => $qty,
					'cost'            => $guest_type->get_unit_price_dollars(),
					'registration_id' => (int) $guest_registration->get_entry_id(),
				),
				$guest_type->get_payment_item_meta()
			);
			$line_items[ 'registration_guest_' . $guest_number ] = new LineItem(
				$meta['label'],
				$meta['quantity'],
				$meta['cost'],
				$meta
			);
		}

		return $line_items;
	}
}
