<?php
declare(strict_types=1);

namespace App\Modules\Payments\Services;

use App\Core\App;
use App\Modules\ServiceCatalog\Models\ServicePrice;

/**
 * Calculates all financial obligations and balances for a member.
 */
final class BalanceCalculator
{
    /**
     * Get complete financial summary for a member.
     */
    public static function getSummary(int $memberId): array
    {
        $db = App::getInstance()->db();

        $member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [$memberId]);
        if (!$member) return [];

        $membershipValue = $member['membership_value'] ?? '0.00';

        // ── Total Paid ──
        $totalPaid = PaymentService::totalPaid($memberId);

        // ── Form Fee ──
        $formFeePaid = PaymentService::hasPaid($memberId, 'form_fee');
        $formFee = ServicePrice::getPrice('SVC_NEW_FORM', '505.00');

        // ── Membership Fee ──
        $membershipFeePaid = PaymentService::hasPaid($memberId, 'membership_fee');
        $membershipFeeAmount = PaymentService::totalPaid($memberId, 'membership_fee');
        $downPaymentAmount = PaymentService::totalPaid($memberId, 'down_payment');
        $membershipPaid = bcadd($membershipFeeAmount, $downPaymentAmount, 2);
        $membershipRemaining = bcsub($membershipValue, $membershipPaid, 2);
        if (bccomp($membershipRemaining, '0', 2) < 0) $membershipRemaining = '0.00';

        // ── Installments ──
        $installmentData = ['total' => '0.00', 'paid' => '0.00', 'remaining' => '0.00', 'overdue_count' => 0, 'next_due' => null];
        try {
            $activePlan = $db->selectOne(
                "SELECT * FROM installment_plans WHERE member_id = ? AND status = 'active' LIMIT 1",
                [$memberId]
            );
            if ($activePlan) {
                $installmentData['total'] = $activePlan['total_with_interest'];
                $paidInstallments = $db->selectOne(
                    "SELECT COALESCE(SUM(paid_amount), 0) as paid FROM installment_schedule WHERE installment_plan_id = ? AND status = 'paid'",
                    [(int) $activePlan['id']]
                );
                $installmentData['paid'] = $paidInstallments['paid'] ?? '0.00';
                $installmentData['remaining'] = bcsub($activePlan['total_with_interest'], bcadd($activePlan['down_payment'], $installmentData['paid'], 2), 2);
                if (bccomp($installmentData['remaining'], '0', 2) < 0) $installmentData['remaining'] = '0.00';

                $overdueRow = $db->selectOne(
                    "SELECT COUNT(*) as cnt FROM installment_schedule WHERE installment_plan_id = ? AND status = 'pending' AND due_date < CURDATE()",
                    [(int) $activePlan['id']]
                );
                $installmentData['overdue_count'] = (int) ($overdueRow['cnt'] ?? 0);

                $nextDue = $db->selectOne(
                    "SELECT due_date, amount FROM installment_schedule WHERE installment_plan_id = ? AND status = 'pending' ORDER BY due_date ASC LIMIT 1",
                    [(int) $activePlan['id']]
                );
                $installmentData['next_due'] = $nextDue;
            }
        } catch (\Throwable $e) {}

        // ── Unpaid Subscriptions ──
        $unpaidSubscriptions = '0.00';
        $unpaidSubsCount = 0;
        try {
            $row = $db->selectOne(
                "SELECT COUNT(*) as cnt, COALESCE(SUM(total_amount - paid_amount + fine_amount), 0) as total 
                 FROM subscriptions WHERE member_id = ? AND status IN ('pending', 'overdue')",
                [$memberId]
            );
            $unpaidSubscriptions = $row['total'] ?? '0.00';
            $unpaidSubsCount = (int) ($row['cnt'] ?? 0);
        } catch (\Throwable $e) {}

        // ── Unpaid Fines ──
        $unpaidFines = '0.00';
        try {
            $row = $db->selectOne(
                "SELECT COALESCE(SUM(amount - paid_amount), 0) as total FROM fines WHERE member_id = ? AND status IN ('imposed', 'appeal_upheld')",
                [$memberId]
            );
            $unpaidFines = $row['total'] ?? '0.00';
        } catch (\Throwable $e) {}

        // ── Total Outstanding ──
        $totalOutstanding = bcadd(
            bcadd($membershipRemaining, $unpaidSubscriptions, 2),
            bcadd($unpaidFines, $installmentData['remaining'], 2),
            2
        );

        return [
            'member_id'              => $memberId,
            'membership_value'       => $membershipValue,
            'total_paid'             => $totalPaid,
            'form_fee_paid'          => $formFeePaid,
            'form_fee'               => $formFee,
            'membership_fee_paid'    => $membershipFeePaid || bccomp($membershipPaid, '0', 2) > 0,
            'membership_paid'        => $membershipPaid,
            'membership_remaining'   => $membershipRemaining,
            'installments'           => $installmentData,
            'unpaid_subscriptions'   => $unpaidSubscriptions,
            'unpaid_subs_count'      => $unpaidSubsCount,
            'unpaid_fines'           => $unpaidFines,
            'total_outstanding'      => $totalOutstanding,
        ];
    }

    /**
     * Check if member can print carnet.
     * Blocked if: unpaid subscriptions, overdue installments, active suspension.
     */
    public static function canPrintCarnet(int $memberId): array
    {
        $summary = self::getSummary($memberId);
        $blocks = [];

        if (bccomp($summary['unpaid_subscriptions'], '0', 2) > 0) {
            $blocks[] = 'اشتراكات غير مدفوعة: ' . money($summary['unpaid_subscriptions']);
        }
        if (($summary['installments']['overdue_count'] ?? 0) > 0) {
            $blocks[] = 'أقساط متأخرة: ' . $summary['installments']['overdue_count'] . ' قسط';
        }
        if (bccomp($summary['unpaid_fines'], '0', 2) > 0) {
            $blocks[] = 'غرامات غير مدفوعة: ' . money($summary['unpaid_fines']);
        }

        return ['allowed' => empty($blocks), 'blocks' => $blocks];
    }
}