<?php
namespace App\Services;

class PaymentEligibilityService
{
    public function isCommissionEligible(array $payment, bool $requiresSepidar = false, bool $adjustmentMode = false): bool
    {
        return $this->resolveCommissionEligibility($payment, $requiresSepidar, $adjustmentMode)['eligible'];
    }

    public function resolveCommissionEligibility(array $payment, bool $requiresSepidar = false, bool $adjustmentMode = false): array
    {
        $amount = (float)($payment['amount'] ?? 0);
        if ($amount <= 0) {
            return $this->result(false, null, 'amount_not_positive');
        }
        if (!empty($payment['is_deleted_placeholder'])) {
            return $this->result(false, null, 'deleted_placeholder');
        }

        $refundStatus = strtoupper(trim((string)($payment['refund_status'] ?? 'NONE')));
        $refundedAmount = (float)($payment['refunded_amount'] ?? 0);
        if ($refundStatus === 'FULL' || ($refundedAmount > 0 && $refundedAmount >= $amount)) {
            return $this->result(false, null, 'fully_refunded');
        }

        $commissionStatus = strtoupper(trim((string)($payment['commission_status'] ?? 'PENDING')));
        if (!$adjustmentMode && in_array($commissionStatus, ['PAID', 'VOID', 'CLAWED_BACK'], true)) {
            return $this->result(false, null, 'commission_status_' . strtolower($commissionStatus));
        }

        if ($requiresSepidar) {
            $financeStatus = strtoupper(trim((string)($payment['finance_status'] ?? 'NONE')));
            if ($financeStatus !== 'SEPIDAR_REGISTERED') {
                return $this->result(false, null, 'sepidar_required');
            }
        }

        if ($this->isCheque($payment)) {
            $chequeStatus = strtolower(trim((string)($payment['cheque_status'] ?? 'pending')));
            $collectionStatus = strtolower(trim((string)($payment['cheque_collection_status'] ?? 'pending')));
            $collectionDate = $this->normalizeDate((string)($payment['cheque_collection_date'] ?? $payment['collection_date'] ?? ''));
            if ($chequeStatus !== 'approved') {
                return $this->result(false, null, 'cheque_not_approved');
            }
            if ($collectionStatus !== 'collected' || $collectionDate === null) {
                return $this->result(false, null, 'cheque_not_collected');
            }
            return $this->result(true, $collectionDate, 'eligible_cheque_collected');
        }

        $effectiveDate = $this->normalizeDate((string)($payment['effective_date'] ?? ''))
            ?: $this->normalizeDate((string)($payment['deposit_date'] ?? ''))
            ?: $this->normalizeDate((string)($payment['payment_date'] ?? ''));
        if ($effectiveDate === null) {
            return $this->result(false, null, 'effective_date_missing');
        }

        return $this->result(true, $effectiveDate, 'eligible_non_cheque');
    }

    public function isCheque(array $payment): bool
    {
        $chequeStatus = strtolower(trim((string)($payment['cheque_status'] ?? 'not_cheque')));
        $collectionStatus = strtolower(trim((string)($payment['cheque_collection_status'] ?? 'not_cheque')));
        $method = strtolower(trim((string)($payment['method'] ?? '')));
        return $chequeStatus !== 'not_cheque'
            || $collectionStatus !== 'not_cheque'
            || strpos($method, 'check') !== false
            || strpos($method, 'cheque') !== false
            || strpos((string)($payment['method'] ?? ''), 'چک') !== false;
    }

    private function result(bool $eligible, ?string $effectiveDate, string $reason): array
    {
        return [
            'eligible' => $eligible,
            'effective_date' => $effectiveDate,
            'reason' => $reason,
        ];
    }

    private function normalizeDate(string $value): ?string
    {
        $value = trim($value);
        if ($value === '') {
            return null;
        }
        if (preg_match('/^(\d{4})-(\d{2})-(\d{2})/', $value, $m) && checkdate((int)$m[2], (int)$m[3], (int)$m[1])) {
            return sprintf('%04d-%02d-%02d', (int)$m[1], (int)$m[2], (int)$m[3]);
        }
        return null;
    }
}
