<?php
/**
 * BookiFlex Payment Extension
 *
 * @package    BookiFlex
 * @subpackage Payment
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Extensions\Payment\Service;

use BookiFlex\Extensions\Payment\Repository\PaymentAllocationRepository;
use BookiFlex\Extensions\Payment\Repository\PaymentQueryFilter;
use BookiFlex\Extensions\Payment\Repository\PaymentRepository;

defined( 'ABSPATH' ) || exit;

/**
 * Payment List Service
 *
 * Orchestrates business logic for payment list operations.
 * Provides data enrichment (allocations) and coordinates repository operations.
 *
 * @package BookiFlex\Extensions\Payment\Service
 */
class PaymentListService
{
    /**
     * Constructor
     *
     * @param PaymentRepository $paymentRepository Payment data access
     * @param PaymentAllocationRepository $paymentAllocationRepository Payment allocation data access
     */
    public function __construct(
        private readonly PaymentRepository $paymentRepository,
        private readonly PaymentAllocationRepository $paymentAllocationRepository,
    ) {
    }

    /**
     * Get payments with enriched allocation data.
     *
     * Fetches paginated payments and enriches them with allocation information
     * (which reservations the payment is allocated to).
     *
     * @param PaymentQueryFilter $filter Filter parameters
     * @return array Structure: ['payments' => Payment[], 'allocations' => array]
     */
    public function getPayments(PaymentQueryFilter $filter): array
    {
        // Fetch payments
        $payments = $this->paymentRepository->findPaginated($filter);

        if (empty($payments)) {
            return [
                'payments' => [],
                'allocations' => [],
            ];
        }

        // Get payment IDs
        $paymentIds = array_map(fn ($p) => $p->getId(), $payments);

        // Fetch allocations for these payments
        $allocations = $this->paymentAllocationRepository->select()
            ->where('payment_id', 'in', $paymentIds)
            ->load('reservation')
            ->fetchAll();

        // Group allocations by payment_id
        $allocationsByPayment = [];
        foreach ($allocations as $allocation) {
            $paymentId = $allocation->getPayment()->getId();
            $reservation = $allocation->getReservation();

            $allocationsByPayment[$paymentId][] = [
                'reservation_number' => $reservation?->getNumber() ?? '',
                'amount' => $allocation->getAmount()->getMinorAmount()->toInt(),
            ];
        }

        return [
            'payments' => $payments,
            'allocations' => $allocationsByPayment,
        ];
    }

    /**
     * Count payments matching filter.
     *
     * Returns total count for pagination, ignoring limit/offset.
     *
     * @param PaymentQueryFilter $filter Filter parameters
     * @return int Total count
     */
    public function countPayments(PaymentQueryFilter $filter): int
    {
        return $this->paymentRepository->countFiltered($filter);
    }

    /**
     * Get payment counts grouped by status.
     *
     * Returns counts for each status (waiting, paid, etc.) to display
     * in filter tabs. Excludes status filter to count across all statuses.
     *
     * @param PaymentQueryFilter $filter Filter parameters (status excluded internally)
     * @return array Associative array: ['status' => count]
     */
    public function getStatusCounts(PaymentQueryFilter $filter): array
    {
        // Get filter without status to count across all statuses
        $filterWithoutStatus = $filter->withoutStatus();
        return $this->paymentRepository->getStatusCounts($filterWithoutStatus);
    }

    /**
     * Delete payments by IDs with audit trail support.
     *
     * Fetches payment details before deletion for audit logging,
     * then performs deletion and returns results.
     *
     * @param array $paymentIds Array of payment IDs to delete
     * @return array Structure: ['deleted' => int, 'payments' => Payment[]]
     */
    public function deletePayments(array $paymentIds): array
    {
        if (empty($paymentIds)) {
            return [
                'deleted' => 0,
                'payments' => [],
            ];
        }

        // Fetch payment details before deletion (for audit trail)
        $payments = $this->paymentRepository->findByIdsWithRelations($paymentIds);

        // Perform deletion
        $deleted = $this->paymentRepository->deleteByIds($paymentIds);

        return [
            'deleted' => $deleted,
            'payments' => $payments,
        ];
    }
}
