<?php
declare(strict_types=1);

namespace App\Modules\Cashier\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\Payments\Services\PaymentService;

final class PaymentRequestService
{
    public static function createRequest(array $data): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $memberId     = (int) ($data['member_id'] ?? 0);
        $paymentType  = $data['payment_type'] ?? '';
        $amount       = $data['amount'] ?? '0.00';
        $description  = $data['description_ar'] ?? '';
        $entityType   = $data['related_entity_type'] ?? null;
        $entityId     = $data['related_entity_id'] ?? null;
        $notes        = $data['notes'] ?? null;
        $currency     = $data['currency'] ?? 'EGP';

        if ($memberId <= 0 && !in_array($paymentType, ['sports_registration', 'hourly_booking', 'sa_form_fee', 'sa_subscription', 'sports_subscription', 'activity_subscription', 'sa_registration_fee'], true)) {
            return ['success' => false, 'error' => 'العضو مطلوب'];
        }
        if ($paymentType === '') {
            return ['success' => false, 'error' => 'نوع الدفعة مطلوب'];
        }
        if (bccomp((string) $amount, '0.01', 2) < 0) {
            return ['success' => false, 'error' => 'المبلغ يجب أن يكون أكبر من صفر'];
        }

        if ($entityType !== null && $entityId !== null) {
            $existing = $db->selectOne(
                "SELECT id, status FROM payment_requests WHERE member_id = ? AND payment_type = ? AND related_entity_type = ? AND related_entity_id = ? AND is_voided = 0 AND status IN ('pending','processing','completed') ORDER BY FIELD(status,'pending','processing','completed') LIMIT 1",
                [$memberId, $paymentType, $entityType, (int) $entityId]
            );
        } else {
            $existing = $db->selectOne(
                "SELECT id, status FROM payment_requests WHERE member_id = ? AND payment_type = ? AND is_voided = 0 AND status IN ('pending','processing') LIMIT 1",
                [$memberId, $paymentType]
            );
        }
        if ($existing) {
            if ($existing['status'] === 'completed') {
                return ['success' => false, 'error' => 'تم دفع هذا البند بالفعل'];
            }
            return ['success' => false, 'error' => 'يوجد طلب دفع معلق بالفعل لنفس النوع'];
        }

        $requestNumber = self::generateNumber($db);
        $branch = App::getInstance()->currentBranch();

        $id = $db->insert('payment_requests', [
            'request_number'      => $requestNumber,
            'member_id'           => $memberId > 0 ? $memberId : null,
            'payment_type'        => $paymentType,
            'amount'              => $amount,
            'currency'            => $currency,
            'description_ar'      => $description,
            'related_entity_type' => $entityType,
            'related_entity_id'   => $entityId ? (int) $entityId : null,
            'status'              => 'pending',
            'requested_by'        => $employee ? (int) $employee->id : 0,
            'branch_id'           => $branch ? (int) $branch['id'] : null,
            'notes'               => $notes,
            'created_at'          => date('Y-m-d H:i:s'),
            'updated_at'          => date('Y-m-d H:i:s'),
        ]);

        EventBus::dispatch('payment_request.created', [
            'request_id'     => $id,
            'request_number' => $requestNumber,
            'member_id'      => $memberId,
            'payment_type'   => $paymentType,
            'amount'         => $amount,
        ]);

        Logger::info("Payment request created", ['id' => $id, 'number' => $requestNumber, 'type' => $paymentType, 'amount' => $amount]);

        return [
            'success'        => true,
            'request_id'     => $id,
            'request_number' => $requestNumber,
        ];
    }

    public static function processRequest(int $requestId, string $paymentMethod): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $request = $db->selectOne(
            "SELECT * FROM payment_requests WHERE id = ? AND is_voided = 0",
            [$requestId]
        );
        if (!$request) {
            return ['success' => false, 'error' => 'طلب الدفع غير موجود'];
        }
        if ($request['status'] === 'completed') {
            return ['success' => false, 'error' => 'طلب الدفع مكتمل بالفعل'];
        }
        if ($request['status'] === 'cancelled') {
            return ['success' => false, 'error' => 'طلب الدفع ملغى'];
        }

        // Atomic lock: mark as processing to prevent double-execution
        $db->query(
            "UPDATE payment_requests SET status = 'processing', updated_at = NOW() WHERE id = ? AND status = 'pending'",
            [$requestId]
        );

        $paymentResult = PaymentService::processPayment([
            'member_id'           => (int) $request['member_id'],
            'amount'              => (string) $request['amount'],
            'payment_type'        => $request['payment_type'],
            'payment_method'      => $paymentMethod,
            'description'         => $request['description_ar'] ?? '',
            'related_entity_type' => $request['related_entity_type'],
            'related_entity_id'   => $request['related_entity_id'] ? (int) $request['related_entity_id'] : null,
            'currency'            => $request['currency'] ?? 'EGP',
        ]);

        if (!$paymentResult['success']) {
            return $paymentResult;
        }

        $now = date('Y-m-d H:i:s');
        $db->update('payment_requests', [
            'status'         => 'completed',
            'payment_id'     => (int) $paymentResult['payment_id'],
            'receipt_number'  => $paymentResult['receipt_number'] ?? null,
            'processed_by'   => $employee ? (int) $employee->id : null,
            'processed_at'   => $now,
            'updated_at'     => $now,
        ], '`id` = ?', [$requestId]);

        EventBus::dispatch('payment_request.completed', [
            'request_id'          => $requestId,
            'request_number'      => $request['request_number'],
            'member_id'           => (int) $request['member_id'],
            'payment_type'        => $request['payment_type'],
            'amount'              => $request['amount'],
            'payment_id'          => $paymentResult['payment_id'],
            'receipt_number'      => $paymentResult['receipt_number'] ?? '',
            'related_entity_type' => $request['related_entity_type'] ?? null,
            'related_entity_id'   => $request['related_entity_id'] ?? null,
        ]);

        Logger::info("Payment request completed", ['id' => $requestId, 'payment_id' => $paymentResult['payment_id']]);

        return [
            'success'        => true,
            'payment_id'     => $paymentResult['payment_id'],
            'receipt_id'     => $paymentResult['receipt_id'] ?? null,
            'receipt_number'  => $paymentResult['receipt_number'] ?? '',
            'request_number' => $request['request_number'],
        ];
    }

    public static function cancelRequest(int $requestId, string $reason = ''): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

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

        $now = date('Y-m-d H:i:s');

        // If completed, also void the linked payment — this IS a true void
        if ($request['status'] === 'completed' && !empty($request['payment_id'])) {
            $paymentResult = \App\Modules\Payments\Services\PaymentService::voidPayment(
                (int) $request['payment_id'],
                $reason ?: 'إلغاء طلب الدفع من الخزينة'
            );
            if (!$paymentResult['success']) {
                return ['success' => false, 'error' => 'فشل إلغاء الدفعة المرتبطة: ' . ($paymentResult['error'] ?? '')];
            }
            // Completed+voided: hide permanently
            $db->update('payment_requests', [
                'status'      => 'cancelled',
                'is_voided'   => 1,
                'voided_at'   => $now,
                'voided_by'   => $employee ? (int) $employee->id : null,
                'void_reason' => $reason,
                'updated_at'  => $now,
            ], '`id` = ?', [$requestId]);
        } else {
            // Pending/processing cancellation: keep visible for re-queue
            $db->update('payment_requests', [
                'status'      => 'cancelled',
                'voided_at'   => $now,
                'voided_by'   => $employee ? (int) $employee->id : null,
                'void_reason' => $reason,
                'updated_at'  => $now,
            ], '`id` = ?', [$requestId]);
        }

        EventBus::dispatch('payment_request.cancelled', [
            'request_id'          => $requestId,
            'member_id'           => (int) $request['member_id'],
            'payment_type'        => $request['payment_type'],
            'related_entity_type' => $request['related_entity_type'] ?? null,
            'related_entity_id'   => (int) ($request['related_entity_id'] ?? 0),
        ]);

        return ['success' => true];
    }

    public static function requeueRequest(int $requestId): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $request = $db->selectOne(
            "SELECT * FROM payment_requests WHERE id = ? AND status = 'cancelled' AND is_voided = 0",
            [$requestId]
        );
        if (!$request) {
            return ['success' => false, 'error' => 'طلب الدفع غير موجود أو لا يمكن إعادته'];
        }

        // Check no duplicate pending request exists for the same entity
        if ($request['related_entity_type'] && $request['related_entity_id']) {
            $existing = $db->selectOne(
                "SELECT id FROM payment_requests WHERE member_id = ? AND payment_type = ? AND related_entity_type = ? AND related_entity_id = ? AND status IN ('pending','processing') AND is_voided = 0 AND id != ?",
                [(int) $request['member_id'], $request['payment_type'], $request['related_entity_type'], (int) $request['related_entity_id'], $requestId]
            );
        } else {
            $existing = $db->selectOne(
                "SELECT id FROM payment_requests WHERE member_id = ? AND payment_type = ? AND status IN ('pending','processing') AND is_voided = 0 AND id != ?",
                [(int) $request['member_id'], $request['payment_type'], $requestId]
            );
        }

        if ($existing) {
            return ['success' => false, 'error' => 'يوجد طلب دفع معلق بالفعل لنفس البند'];
        }

        $now = date('Y-m-d H:i:s');
        $db->update('payment_requests', [
            'status'      => 'pending',
            'voided_at'   => null,
            'voided_by'   => null,
            'void_reason' => null,
            'updated_at'  => $now,
        ], '`id` = ?', [$requestId]);

        Logger::info("Payment request re-queued", ['id' => $requestId, 'by' => $employee ? (int) $employee->id : 0]);

        return ['success' => true, 'request_number' => $request['request_number']];
    }

    public static function getPendingQueue(?int $branchId = null, array $filters = []): array
    {
        $db = App::getInstance()->db();
        $where = "pr.is_voided = 0";
        $params = [];

        $status = $filters['status'] ?? '';
        if ($status !== '') {
            $where .= ' AND pr.status = ?';
            $params[] = $status;
        } else {
            $where .= " AND pr.status IN ('pending','processing')";
        }

        if ($branchId !== null && $branchId > 0) {
            $where .= ' AND pr.branch_id = ?';
            $params[] = $branchId;
        }

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

        $search = trim($filters['search'] ?? '');
        if ($search !== '') {
            $where .= ' AND (m.full_name_ar LIKE ? OR m.form_number LIKE ? OR pr.request_number LIKE ?)';
            $term = '%' . $search . '%';
            $params = array_merge($params, [$term, $term, $term]);
        }

        return $db->select(
            "SELECT pr.*, m.full_name_ar as member_name, m.form_number, m.membership_number,
                    e.full_name_ar as requested_by_name,
                    pay.receipt_id
             FROM payment_requests pr
             LEFT JOIN members m ON m.id = pr.member_id
             LEFT JOIN employees e ON e.id = pr.requested_by
             LEFT JOIN payments pay ON pay.id = pr.payment_id
             WHERE {$where}
             ORDER BY pr.created_at ASC
             LIMIT 200",
            $params
        );
    }

    public static function getForMember(int $memberId): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT * FROM payment_requests WHERE member_id = ? AND is_voided = 0 ORDER BY id DESC LIMIT 50",
            [$memberId]
        );
    }

    private static function generateNumber($db): string
    {
        $year = date('Y');
        $row = $db->selectOne(
            "SELECT MAX(CAST(SUBSTRING(request_number, 10) AS UNSIGNED)) as max_num
             FROM payment_requests WHERE request_number LIKE ?",
            ["PRQ-{$year}-%"]
        );
        $next = ((int) ($row['max_num'] ?? 0)) + 1;
        return sprintf('PRQ-%s-%06d', $year, $next);
    }

    public static function getPaymentTypeLabel(string $type): string
    {
        return match ($type) {
            'form_fee'              => 'رسوم استمارة',
            'membership_fee'        => 'رسوم عضوية',
            'down_payment'          => 'مقدم أقساط',
            'addition_fee'          => 'رسوم إضافة',
            'annual_subscription'   => 'اشتراك سنوي',
            'divorce_fee'           => 'رسوم طلاق',
            'death_fee'             => 'رسوم وفاة',
            'waiver_fee'            => 'رسوم تنازل',
            'separation_fee'        => 'رسوم فصل',
            'fine'                  => 'غرامة',
            'carnet_replacement'    => 'بدل فاقد كارنيه',
            'sports_registration'   => 'تسجيل رياضي',
            'sa_registration_fee'   => 'رسوم تسجيل نشاط رياضي',
            'activity_subscription' => 'اشتراك نشاط',
            'seasonal_fee'          => 'رسوم عضوية موسمية',
            'foreign_membership_fee' => 'رسوم عضوية أجنبية',
            'sports_membership_fee' => 'رسوم عضوية رياضية',
            default                 => $type,
        };
    }
}
