<?php
namespace RadiusTheme\RadiusBooking\Repositories;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}
use RadiusTheme\RadiusBooking\Abstracts\BaseRepository;
use RadiusTheme\RadiusBooking\Models\Payment;

/**
 * Class PaymentRepository
 *
 * Handles data operations for the Payment model.
 */
class PaymentRepository extends BaseRepository {

	/**
	 * The model class managed by this repository.
	 *
	 * @var string
	 */
	protected string $model = Payment::class;

	/**
	 * Updates an existing payment record with the specified data.
	 *
	 * @param int|string $id The unique identifier of the payment to update.
	 * @param array $paymentData An associative array of payment data to update.
	 *
	 * @return bool|mixed Returns the updated payment record on success or false on failure.
	 */
	public function updatePayment( $id, $paymentData ) {
		$payment = $this->update( $id, $paymentData );
		if ( $payment ) {
			do_action( 'rtrb_appointment_payment_updated', $id, $paymentData );
		}
		return $payment;
	}

	/**
	 * Calculates the total payment amount made by a specific customer.
	 *
	 * @param mixed $customerId The unique identifier of the customer whose total payment is to be calculated.
	 *
	 * @return float The total payment amount made by the specified customer.
	 */
	public function getCustomerTotalPaymentPrice( $customerId ) {
		$payments = $this->model::where( 'customer_id', $customerId )->get();
		$total    = 0.0;

		foreach ( $payments as $payment ) {
			$total += $payment->amount;
		}
		return $total;
	}

	/**
	 * Retrieves the total collected revenue for a specific day based on the given date.
	 *
	 * @param string $dayDate The date for which the revenue is to be calculated, in the format 'YYYY-MM-DD'.
	 *
	 * @return float The total revenue collected on the specified date.
	 */
	public function getDailyCollectedRevenue( string $dayDate ): float {
		return $this->model::whereIn( 'status', array( 'paid', 'partial_payment' ) )
							->whereBetween(
								'booking_date_time',
								array(
									$dayDate . ' 00:00:00',
									$dayDate . ' 23:59:59',
								)
							)
							->sum( 'amount' );
	}

	/**
	 * Calculates the total pending revenue for a specific day based on the provided date.
	 *
	 * @param string $dayDate The date for which the pending revenue is to be calculated, formatted as 'YYYY-MM-DD'.
	 *
	 * @return float The total pending revenue for the specified day.
	 */
	public function getDailyPendingRevenue( string $dayDate ): float {
		return $this->model::whereIn( 'status', array( 'paid', 'partial_payment', 'pending', 'completed' ) )
							->whereBetween(
								'booking_date_time',
								array(
									$dayDate . ' 00:00:00',
									$dayDate . ' 23:59:59',
								)
							)
							->sum( 'amount' );
	}

	/**
	 * Retrieves dashboard data including total revenue, total paid amount, total partially paid amount, and total pending amount.
	 *
	 * @return array An associative array containing the following keys:
	 *               - 'total_revenue': The total revenue across all applicable statuses.
	 *               - 'total_paid': The total amount collected with the 'paid' status.
	 *               - 'total_partial': The total amount collected with the 'partial_payment' status.
	 *               - 'total_pending': The total pending amount calculated as the difference between total revenue and total paid.
	 */
	public function getDashboardData() {
		$total_revenue = $this->model::whereIn( 'status', array( 'paid', 'partial_payment', 'pending', 'completed' ) )->sum( 'amount' );
		$total_paid    = $this->model::where( 'status', 'paid' )->sum( 'amount' );
		$total_partial = $this->model::where( 'status', 'partial_payment' )->sum( 'amount' );
		return array(
			'total_revenue' => $total_revenue,
			'total_paid'    => $total_paid,
			'total_partial' => $total_partial,
			'total_pending' => $total_revenue - $total_paid,
		);
	}

	/**
	 * Paginate payments with multi-column search support.
	 *
	 * Searches across id, booking_id (shown as appointment ID), and transaction_id.
	 *
	 * @param int         $perPage Number of items per page.
	 * @param int         $page    Current page number.
	 * @param string      $order   Order direction.
	 * @param string      $orderBy Column to order by.
	 * @param string|null $search  Search term.
	 * @param string|null $status  Payment status filter.
	 * @param string|null $type    Booking type filter (service|meeting|event).
	 *
	 * @return mixed Paginated results.
	 */
	public function paginateWithSearch( $perPage, $page, $order, $orderBy, $search = null, $status = null, $type = null ) {
		$query = $this->model::query();

		if ( $status && 'all' !== $status ) {
			$query->where( 'status', $status );
		}

		if ( $type && 'all' !== $type ) {
			if ( 'meeting' === $type || 'event' === $type ) {
				$query->where( 'booking_type', $type );
			} else {
				// Anything that isn't a meeting or event is a service booking
				// (covers 'service', the legacy 'service_booking' default, etc.).
				$query->whereNotIn( 'booking_type', array( 'meeting', 'event' ) );
			}
		}

		if ( $search ) {
			$query->where(
				function ( $q ) use ( $search ) {
//					$q->where( 'transaction_id', 'LIKE', '%' . $search . '%' );
					$q->where( 'transaction_id', '=',  $search);
					if ( is_numeric( $search ) ) {
						$q->orWhere( 'id', intval( $search ) );
//						$q->orWhere( 'booking_id', intval( $search ) );
					}
				}
			);
		}

		return $query->paginate( $perPage, $page, $order, $orderBy );
	}

	public function getPaymentStatusByAmount($paymentId)
	{
		$payment = $this->model::where('id', $paymentId)->first();

		if (!$payment) {
			return 'pending';
		}

		$amount       = (float) ($payment->amount ?? 0);
		$total_amount = (float) ($payment->total_amount ?? 0);
		$due_amount   = (float) ($payment->due_amount ?? 0);

		if ($amount >= $total_amount && $due_amount <= 0) {
			return 'paid';
		}

		if ($amount > 0 && $amount < $total_amount) {
			return 'partial_payment';
		}

		return 'pending';
	}
}
