<?php
declare(strict_types=1);

namespace App\Modules\Payments\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;

/**
 * Central payment processor — EVERY payment in the system goes through here.
 * Creates payment + receipt in a single transaction.
 * 
 * Payment Types:
 *   form_fee              رسوم استمارة          505 ج.م
 *   membership_fee        قيمة العضوية          150,000 / 225,000 / 300,000
 *   addition_fee          رسوم إضافة (زوجة/ابن/مؤقت)
 *   annual_subscription   اشتراك سنوي           492 + 35 تنمية = 527
 *   development_fee       رسوم تنمية            35 ج.م
 *   down_payment          مقدم تقسيط            25% minimum
 *   installment           قسط شهري
 *   fine                  غرامة مخالفة          1,000 - 10,000
 *   separation_fee        رسوم فصل              30%/20%/15%/10%/5%/2.5%
 *   divorce_fee           رسوم طلاق             10% or 50%
 *   death_fee             رسوم وفاة (استمارة + اشتراك)
 *   waiver_fee            رسوم تنازل            30%
 *   carnet_replacement    بدل فاقد كارنيه
 *   seasonal_fee          رسوم عضوية موسمية
 *   sports_conversion     رسوم تحويل رياضي      50%
 *   other                 أخرى
 */
final class PaymentService
{
    /**
     * Process a payment and create receipt.
     * Returns ['success' => bool, 'payment_id' => int, 'receipt_id' => int, 'receipt_number' => string]
     */
    public static function processPayment(array $data): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        // Validate required fields
        $memberId = isset($data['member_id']) && $data['member_id'] !== null ? (int) $data['member_id'] : null;
        $amount = $data['amount'] ?? '0.00';
        $paymentType = $data['payment_type'] ?? '';
        $paymentMethod = $data['payment_method'] ?? 'cash';
        $description = $data['description'] ?? '';
        $guestName = $data['guest_name'] ?? null;

        if (bccomp((string) $amount, '0.01', 2) < 0) {
            return ['success' => false, 'error' => 'المبلغ يجب أن يكون أكبر من صفر'];
        }
        if ($paymentType === '') {
            return ['success' => false, 'error' => 'نوع الدفعة مطلوب'];
        }

        // Verify member exists (skip for guest payments)
        $member = null;
        if ($memberId !== null && $memberId > 0) {
            $member = $db->selectOne("SELECT id, full_name_ar, form_number FROM members WHERE id = ? AND is_archived = 0", [$memberId]);
            if (!$member) {
                return ['success' => false, 'error' => 'العضو غير موجود'];
            }
        }

        $db->beginTransaction();
        try {
            // Generate receipt number
            $receiptNumber = self::generateReceiptNumber();

            // Create payment record
            $paymentId = $db->insert('payments', [
                'member_id'               => ($memberId !== null && $memberId > 0) ? $memberId : null,
                'payment_type'            => $paymentType,
                'amount'                  => $amount,
                'currency'                => $data['currency'] ?? 'EGP',
                'payment_method'          => $paymentMethod,
                'check_number'            => $data['check_number'] ?? null,
                'check_bank'              => $data['check_bank'] ?? null,
                'check_date'              => $data['check_date'] ?? null,
                'check_status'            => $paymentMethod === 'check' ? 'pending' : null,
                'visa_reference'          => $data['visa_reference'] ?? null,
                'transfer_reference'      => $data['transfer_reference'] ?? null,
                'transfer_bank'           => $data['transfer_bank'] ?? null,
                'related_entity_type'     => $data['related_entity_type'] ?? null,
                'related_entity_id'       => $data['related_entity_id'] ?? null,
                'notes'                   => $data['notes'] ?? ($guestName ? $description . ' — ' . $guestName : $description),
                'payment_date'            => $data['payment_date'] ?? date('Y-m-d'),
                'received_by_employee_id' => $employee ? (int) $employee->id : null,
                'treasury_id'             => isset($data['treasury_id']) ? (int) $data['treasury_id'] : null,
                'session_id'              => isset($data['session_id']) ? (int) $data['session_id'] : null,
                'is_voided'               => 0,
                'created_at'              => date('Y-m-d H:i:s'),
                'updated_at'              => date('Y-m-d H:i:s'),
                'created_by'              => $employee ? (int) $employee->id : null,
            ]);

            // Auto-generate description if empty
            if ($description === '') {
                $description = self::getPaymentTypeLabel($paymentType);
                if ($member && $member['form_number']) {
                    $description .= ' — استمارة ' . $member['form_number'];
                }
            }

            // Create receipt
            $receiptId = $db->insert('receipts', [
                'receipt_number'        => $receiptNumber,
                'member_id'             => ($memberId !== null && $memberId > 0) ? $memberId : null,
                'payment_id'            => $paymentId,
                'receipt_type'          => 'payment',
                'amount'                => $amount,
                'amount_in_words_ar'    => number_to_arabic_words((float) $amount),
                'description_ar'        => $description,
                'issued_by_employee_id' => $employee ? (int) $employee->id : null,
                'issued_at'             => date('Y-m-d H:i:s'),
                'is_voided'             => 0,
                'print_count'           => 0,
                'created_at'            => date('Y-m-d H:i:s'),
            ]);

            // Link receipt to payment
            $db->update('payments', ['receipt_id' => $receiptId], '`id` = ?', [$paymentId]);

            $db->commit();

            // Fire event
            EventBus::dispatch('payment.completed', [
                'payment_id'     => $paymentId,
                'receipt_id'     => $receiptId,
                'receipt_number' => $receiptNumber,
                'member_id'      => ($memberId !== null && $memberId > 0) ? $memberId : 0,
                'payment_type'   => $paymentType,
                'amount'         => $amount,
                'method'         => $paymentMethod,
                'treasury_id'    => isset($data['treasury_id']) ? (int) $data['treasury_id'] : null,
            ]);

            Logger::info("Payment processed", [
                'payment_id' => $paymentId,
                'member_id'  => $memberId ?? 0,
                'type'       => $paymentType,
                'amount'     => $amount,
            ]);

            return [
                'success'        => true,
                'payment_id'     => $paymentId,
                'receipt_id'     => $receiptId,
                'receipt_number' => $receiptNumber,
                'amount'         => $amount,
            ];

        } catch (\Throwable $e) {
            $db->rollBack();
            Logger::error("Payment failed: " . $e->getMessage(), [
                'member_id' => $memberId ?? 0,
                'type'      => $paymentType,
                'amount'    => $amount,
            ]);
            return ['success' => false, 'error' => 'فشل تسجيل الدفع: ' . $e->getMessage()];
        }
    }

    /**
     * Void a payment and its receipt.
     */
    public static function voidPayment(int $paymentId, string $reason): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $payment = $db->selectOne("SELECT * FROM payments WHERE id = ? AND is_voided = 0", [$paymentId]);
        if (!$payment) {
            return ['success' => false, 'error' => 'الدفعة غير موجودة أو ملغاة بالفعل'];
        }

        // Check 24-hour void window (unless super admin)
        $hoursSince = (time() - strtotime($payment['created_at'])) / 3600;
        $isSuperAdmin = false;
        if ($employee) {
            try {
                $sa = $db->selectOne(
                    "SELECT 1 FROM employee_roles er JOIN roles r ON r.id = er.role_id 
                     WHERE er.employee_id = ? AND r.role_code = 'super_admin' AND er.is_active = 1 LIMIT 1",
                    [(int) $employee->id]
                );
                $isSuperAdmin = ($sa !== null);
            } catch (\Throwable $e) {}
        }

        if ($hoursSince > 24 && !$isSuperAdmin) {
            return ['success' => false, 'error' => 'لا يمكن إلغاء الدفعة بعد 24 ساعة — يتطلب صلاحية مدير النظام'];
        }

        $db->beginTransaction();
        try {
            // Void the payment
            $db->update('payments', [
                'is_voided'  => 1,
                'voided_at'  => date('Y-m-d H:i:s'),
                'voided_by'  => $employee ? (int) $employee->id : null,
                'void_reason' => $reason,
                'updated_at' => date('Y-m-d H:i:s'),
            ], '`id` = ?', [$paymentId]);

            // Void the receipt
            if ($payment['receipt_id']) {
                $db->update('receipts', [
                    'is_voided'  => 1,
                    'voided_at'  => date('Y-m-d H:i:s'),
                    'voided_by'  => $employee ? (int) $employee->id : null,
                    'void_reason' => $reason,
                ], '`id` = ?', [(int) $payment['receipt_id']]);
            }

            // Void any linked payment_requests that reference this payment
            $db->query(
                "UPDATE payment_requests SET status = 'voided', is_voided = 1, updated_at = NOW() WHERE payment_id = ? AND is_voided = 0",
                [$paymentId]
            );

            $db->commit();

            EventBus::dispatch('payment.voided', [
                'payment_id'   => $paymentId,
                'member_id'    => (int) $payment['member_id'],
                'payment_type' => $payment['payment_type'],
                'amount'       => $payment['amount'],
                'reason'       => $reason,
            ]);

            return ['success' => true];

        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => 'فشل الإلغاء: ' . $e->getMessage()];
        }
    }

    /**
     * Check if a specific payment type has been paid for a member.
     */
    public static function hasPaid(int $memberId, string $paymentType, ?string $relatedEntityType = null, ?int $relatedEntityId = null): bool
    {
        $db = App::getInstance()->db();
        $where = 'member_id = ? AND payment_type = ? AND is_voided = 0';
        $params = [$memberId, $paymentType];

        if ($relatedEntityType !== null) {
            $where .= ' AND related_entity_type = ?';
            $params[] = $relatedEntityType;
        }
        if ($relatedEntityId !== null) {
            $where .= ' AND related_entity_id = ?';
            $params[] = $relatedEntityId;
        }

        $row = $db->selectOne("SELECT COUNT(*) as cnt FROM payments WHERE {$where}", $params);
        return (int) ($row['cnt'] ?? 0) > 0;
    }

    /**
     * Get total paid for a member of a specific type.
     */
    public static function totalPaid(int $memberId, ?string $paymentType = null): string
    {
        $db = App::getInstance()->db();
        $where = 'member_id = ? AND is_voided = 0';
        $params = [$memberId];

        if ($paymentType !== null) {
            $where .= ' AND payment_type = ?';
            $params[] = $paymentType;
        }

        $row = $db->selectOne("SELECT COALESCE(SUM(amount), 0) as total FROM payments WHERE {$where}", $params);
        return $row['total'] ?? '0.00';
    }

    /**
     * Generate unique receipt number.
     */
    public static function generateReceiptNumber(): string
    {
        $db = App::getInstance()->db();
        $year = date('Y');
        $prefix = 'REC-' . $year . '-';
        $last = $db->selectOne(
            "SELECT receipt_number FROM receipts WHERE receipt_number LIKE ? ORDER BY id DESC LIMIT 1",
            [$prefix . '%']
        );
        if ($last) {
            $parts = explode('-', $last['receipt_number']);
            $seq = (int) end($parts) + 1;
        } else {
            $seq = 1;
        }
        return $prefix . str_pad((string) $seq, 6, '0', STR_PAD_LEFT);
    }

    /**
     * Get Arabic label for payment type.
     */
    public static function getPaymentTypeLabel(string $type): string
    {
        return match ($type) {
            'form_fee'            => 'رسوم استمارة',
            'membership_fee'      => 'قيمة العضوية',
            'addition_fee'        => 'رسوم إضافة',
            'annual_subscription' => 'اشتراك سنوي',
            'development_fee'     => 'رسوم تنمية',
            'down_payment'        => 'مقدم تقسيط',
            'installment'         => 'قسط شهري',
            'fine'                => 'غرامة',
            'separation_fee'      => 'رسوم فصل',
            'divorce_fee'         => 'رسوم طلاق',
            'death_fee'           => 'رسوم نقل وفاة',
            'waiver_fee'          => 'رسوم تنازل',
            'carnet_replacement'  => 'بدل فاقد كارنيه',
            'seasonal_fee'        => 'رسوم عضوية موسمية',
            'sports_conversion'   => 'رسوم تحويل رياضي',
            'inventory_sale'          => 'مبيعات مخزون',
            'activity_subscription'   => 'اشتراك نشاط',
            'other'               => 'أخرى',
            default               => $type,
        };
    }
}