<?php

namespace App\Actions;

use App\Models\Recharge;
use App\Models\RechargeSetting;
use App\Models\User;
use App\Models\BalanceLog;
use App\Models\IncomeHistory;
use App\Services\VoucherTransactionService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class RechargeFinalizer
{
    public function markSuccess(int $rechargeId, array $apiRes = [], string $note = ''): void
    {
        DB::transaction(function () use ($rechargeId, $apiRes, $note) {
            $r = Recharge::lockForUpdate()->findOrFail($rechargeId);

            if ($r->status === 'success') return;
            if ($r->status === 'failed') return;
            if ($r->status !== 'pending') return;

            $r->status = 'success';
            $r->last_response = $apiRes;
            $r->save();

            $u = User::lockForUpdate()->findOrFail($r->user_id);

            if (!$r->cashback_applied && (float)$r->cashback > 0) {
                $before = (float)($u->balance ?? 0);
                $after  = $before + (float)$r->cashback;

                $u->balance = $after;
                $u->save();

                $r->cashback_applied = true;
                $r->save();

                // Optional logs
                if (class_exists(BalanceLog::class)) {
                    BalanceLog::create([
                        'user_id' => $u->id,
                        'amount'  => (float)$r->cashback,
                    ]);
                }

                if (class_exists(IncomeHistory::class)) {
                    IncomeHistory::create([
                        'user_id'     => $u->id,
                        'source'      => 'recharge_cashback',
                        'amount'      => (float)$r->cashback,
                        'description' => 'রিচার্জ ক্যাশব্যাক ' . (float)$r->cashback . '৳ যুক্ত হয়েছে। TRX: ' . $r->tran_id . ($note ? " ({$note})" : ''),
                    ]);
                }
            }

            $this->applyUplineCommissions($u, $r);
        });
    }

    public function markFailed(int $rechargeId, array $apiRes = [], string $note = ''): void
    {
        DB::transaction(function () use ($rechargeId, $apiRes, $note) {
            $r = Recharge::lockForUpdate()->findOrFail($rechargeId);

            if ($r->status === 'failed') return;
            if ($r->status === 'success') return;
            if ($r->status !== 'pending') return;

            $r->status = 'failed';
            $r->last_response = $apiRes;
            $r->save();

            if (!$r->debited || $r->refunded) return;

            $u = User::lockForUpdate()->findOrFail($r->user_id);

            $before = (float)($u->voucher_balance ?? 0);
            $after  = $before + (float)$r->amount;

            $u->voucher_balance = $after;
            $u->save();

            $r->refunded = true;
            $r->save();

            VoucherTransactionService::record(
                userId: (int) $u->id,
                direction: 'credit',
                amount: (float) $r->amount,
                before: $before,
                after: $after,
                source: 'mobile_recharge_refund',
                description: 'রিচার্জ ব্যর্থ হওয়ায় রিচার্জ #' . $r->id . ' ভাউচার রিফান্ড। TRX: ' . $r->tran_id,
                referenceType: 'recharge',
                referenceId: $r->id,
                metadata: [
                    'tran_id' => $r->tran_id,
                ]
            );

            if (class_exists(IncomeHistory::class)) {
                IncomeHistory::create([
                    'user_id'     => $u->id,
                    'source'      => 'recharge_refund',
                    'amount'      => (float)$r->amount,
                    'description' => 'রিচার্জ ব্যর্থ হওয়ায় ভাউচারে ' . (float)$r->amount . '৳ রিফান্ড। TRX: ' . $r->tran_id . ($note ? " ({$note})" : ''),
                ]);
            }
        });
    }

    public function rejectSuccess(int $rechargeId, string $note = ''): void
    {
        DB::transaction(function () use ($rechargeId, $note) {
            $r = Recharge::lockForUpdate()->findOrFail($rechargeId);

            if ($r->status !== 'success') {
                return;
            }

            $existing = is_array($r->last_response) ? $r->last_response : [];
            $existing['admin_action'] = 'reject_success';
            $existing['admin_note'] = $note;
            $existing['admin_at'] = now()->toDateTimeString();

            $r->status = 'failed';
            $r->last_response = $existing;
            $r->save();

            $u = User::lockForUpdate()->findOrFail($r->user_id);

            // Reverse cashback
            if ($r->cashback_applied && (float) $r->cashback > 0) {
                $cashback = (float) $r->cashback;
                $before = (float) ($u->balance ?? 0);
                $after = $before - $cashback;

                $u->balance = $after;
                $u->save();

                $r->cashback_applied = false;
                $r->save();

                if (class_exists(BalanceLog::class)) {
                    BalanceLog::create([
                        'user_id' => $u->id,
                        'amount' => -1 * $cashback,
                    ]);
                }

                if (class_exists(IncomeHistory::class)) {
                    IncomeHistory::create([
                        'user_id' => $u->id,
                        'source' => 'recharge_cashback_reversal',
                        'amount' => -1 * $cashback,
                        'description' => 'রিভার্সাল: রিচার্জ ক্যাশব্যাক ' . $cashback . '৳ সমন্বয় করা হয়েছে। TRX: ' . $r->tran_id . ($note ? " ({$note})" : ''),
                    ]);
                }
            }

            $this->reverseUplineCommissions($u, $r, $note);

            // Refund voucher if debited and not refunded yet
            if ($r->debited && !$r->refunded) {
                $beforeVoucher = (float) ($u->voucher_balance ?? 0);
                $afterVoucher = $beforeVoucher + (float) $r->amount;

                $u->voucher_balance = $afterVoucher;
                $u->save();

                $r->refunded = true;
                $r->save();

                VoucherTransactionService::record(
                    userId: (int) $u->id,
                    direction: 'credit',
                    amount: (float) $r->amount,
                    before: $beforeVoucher,
                    after: $afterVoucher,
                    source: 'mobile_recharge_refund',
                    description: 'অ্যাডমিন রিজেক্ট: রিচার্জ #' . $r->id . ' ভাউচার রিফান্ড। TRX: ' . $r->tran_id,
                    referenceType: 'recharge',
                    referenceId: $r->id,
                    metadata: [
                        'tran_id' => $r->tran_id,
                        'admin_reject' => true,
                    ]
                );

                if (class_exists(IncomeHistory::class)) {
                    IncomeHistory::create([
                        'user_id'     => $u->id,
                        'source'      => 'recharge_refund',
                        'amount'      => (float) $r->amount,
                        'description' => 'রিচার্জ রিজেক্ট হওয়ায় ভাউচার রিফান্ড ' . (float) $r->amount . '৳। TRX: ' . $r->tran_id . ($note ? " ({$note})" : ''),
                    ]);
                }
            }
        });
    }

    private function applyUplineCommissions(User $user, Recharge $recharge): void
    {
        $setting = RechargeSetting::one();
        $commissions = $setting->upline_commissions ?? [];

        if (!is_array($commissions) || count($commissions) === 0) {
            return;
        }

        $level = 1;
        $upline = $user->upline();
        $applied = [];

        foreach ($commissions as $amount) {
            if (!$upline) {
                break;
            }

            $commission = (float) $amount;

            if ($commission > 0) {
                $upline->increment('balance', $commission);
                $applied[] = [
                    'user_id' => (int) $upline->id,
                    'amount' => $commission,
                    'level' => $level,
                ];

                if (class_exists(BalanceLog::class)) {
                    BalanceLog::create([
                        'user_id' => $upline->id,
                        'amount'  => $commission,
                    ]);
                }

                if (class_exists(IncomeHistory::class)) {
                    IncomeHistory::create([
                        'user_id'     => $upline->id,
                        'source'      => 'recharge_upline_commission',
                        'amount'      => $commission,
                        'description' => "অভিনন্দন! আপনি {$level}য় লেভেলের {$user->name} ({$user->referral_code}) এর রিচার্জ থেকে {$commission}৳ কমিশন পেয়েছেন। TRX: {$recharge->tran_id}",
                    ]);
                }
            }

            $upline = $upline->upline();
            $level++;
        }

        if ($applied !== [] && Schema::hasColumn('recharges', 'upline_commissions_applied')) {
            $recharge->upline_commissions_applied = $applied;
            $recharge->save();
        }
    }

    private function reverseUplineCommissions(User $user, Recharge $recharge, string $note = ''): void
    {
        $snapshot = is_array($recharge->upline_commissions_applied)
            ? $recharge->upline_commissions_applied
            : [];

        if ($snapshot === []) {
            $setting = RechargeSetting::one();
            $commissions = $setting->upline_commissions ?? [];
            $level = 1;
            $upline = $user->upline();
            foreach ($commissions as $amount) {
                if (!$upline) {
                    break;
                }
                $commission = (float) $amount;
                if ($commission > 0) {
                    $snapshot[] = [
                        'user_id' => (int) $upline->id,
                        'amount' => $commission,
                        'level' => $level,
                    ];
                }
                $upline = $upline->upline();
                $level++;
            }
        }

        foreach ($snapshot as $row) {
            $uplineId = (int) ($row['user_id'] ?? 0);
            $commission = (float) ($row['amount'] ?? 0);
            $level = (int) ($row['level'] ?? 0);

            if ($uplineId <= 0 || $commission <= 0) {
                continue;
            }

            $uplineUser = User::lockForUpdate()->find($uplineId);
            if (!$uplineUser) {
                continue;
            }

            $before = (float) ($uplineUser->balance ?? 0);
            $after = $before - $commission;
            $uplineUser->balance = $after;
            $uplineUser->save();

            if (class_exists(BalanceLog::class)) {
                BalanceLog::create([
                    'user_id' => $uplineUser->id,
                    'amount' => -1 * $commission,
                ]);
            }

            if (class_exists(IncomeHistory::class)) {
                $abs = abs($commission);
                $levelText = $level > 0 ? $level . 'য় লেভেলের ' : '';
                IncomeHistory::create([
                    'user_id' => $uplineUser->id,
                    'source' => 'recharge_upline_reversal',
                    'amount' => -1 * $commission,
                    'description' => "রিভার্সাল: {$levelText}{$user->name} ({$user->referral_code}) এর রিচার্জ কমিশন {$abs}৳ সমন্বয় করা হয়েছে। TRX: {$recharge->tran_id}" . ($note ? " ({$note})" : ''),
                ]);
            }
        }
    }
}
