﻿<?php

use App\Models\Contribution;
use App\Models\Transaction;
use App\Services\MpesaService;
use Illuminate\Support\Facades\DB;
use Livewire\Component;

new class extends Component
{
    public Contribution $contribution;

    public string $payment_method = 'manual';

    public string $payment_reference = '';

    public string $notes = '';

    public function mount(Contribution $contribution): void
    {
        $this->contribution = $contribution->load([
            'chama',
            'fund',
            'contributionPlan',
            'user',
        ]);

        abort_unless(
            $this->canPayContribution(),
            403
        );
    }

    private function canPayContribution(): bool
    {
        if ($this->contribution->user_id === auth()->id()) {
            return true;
        }

        return $this->contribution->chama->members()
            ->where('user_id', auth()->id())
            ->where('status', 'active')
            ->whereIn('role', ['chairperson', 'admin', 'treasurer'])
            ->exists();
    }

    public function isPaid(): bool
    {
        return $this->contribution->status === 'paid';
    }

    public function pendingMpesaTransaction(): ?Transaction
    {
        return Transaction::query()
            ->where('contribution_id', $this->contribution->id)
            ->where('payment_method', 'mpesa')
            ->where('status', 'pending')
            ->latest('id')
            ->first();
    }

    public function hasPendingMpesaPayment(): bool
    {
        return $this->pendingMpesaTransaction() !== null;
    }

    public function refreshMpesaStatus(): void
    {
        abort_unless(
            $this->canPayContribution(),
            403
        );

        $this->contribution->refresh();

        if ($this->contribution->status === 'paid') {
            $transaction = $this->pendingMpesaTransaction();

            if ($transaction) {
                $transaction->update([
                    'status' => 'failed',
                    'description' => 'M-PESA payment abandoned because the contribution was already paid.',
                    'processed_at' => now(),
                ]);
            }

            return;
        }

        $transaction = $this->pendingMpesaTransaction();

        if (! $transaction) {
            return;
        }

        if (! $transaction->gateway_reference) {
            $this->addError(
                'payment_method',
                'The M-PESA payment request is still being prepared. Please wait a moment and try again.'
            );

            return;
        }

        try {
            $response = app(MpesaService::class)->queryStkPush(
                $transaction->gateway_reference
            );

            $resultCode = (string) ($response['ResultCode'] ?? '');

            if (($response['success'] ?? false) && $resultCode === '0') {
                $items = data_get(
                    $response,
                    'CallbackMetadata.Item',
                    []
                );

                $metadata = collect($items)
                    ->mapWithKeys(function ($item) {
                        $name = data_get($item, 'Name');

                        return $name
                            ? [$name => data_get($item, 'Value')]
                            : [];
                    });

                $mpesaReceipt = $metadata->get('MpesaReceiptNumber');

                if (! $mpesaReceipt) {
                    $this->addError(
                        'payment_method',
                        'M-PESA reported a successful payment but no receipt number was returned. Please try again.'
                    );

                    return;
                }

                DB::transaction(function () use ($transaction, $mpesaReceipt) {
                    $lockedTransaction = Transaction::query()
                        ->whereKey($transaction->id)
                        ->lockForUpdate()
                        ->firstOrFail();

                    if ($lockedTransaction->status !== 'pending') {
                        return;
                    }

                    $contribution = Contribution::query()
                        ->whereKey($lockedTransaction->contribution_id)
                        ->lockForUpdate()
                        ->firstOrFail();

                    if ($contribution->status === 'paid') {
                        $lockedTransaction->update([
                            'status' => 'failed',
                            'description' => 'M-PESA payment abandoned because the contribution was already paid.',
                            'processed_at' => now(),
                        ]);

                        return;
                    }

                    $contribution->update([
                        'status' => 'paid',
                        'paid_at' => now(),
                        'payment_reference' => $mpesaReceipt,
                        'payment_method' => 'mpesa',
                    ]);

                    $lockedTransaction->update([
                        'status' => 'completed',
                        'external_reference' => $mpesaReceipt,
                        'description' => 'M-PESA contribution payment',
                        'processed_at' => now(),
                    ]);
                });

                $this->contribution->refresh();

                return;
            }

            if (
                ($response['error_code'] ?? null) === '500.001.1001'
            ) {
                $this->addError(
                    'payment_method',
                    'M-PESA has not finalized this payment request yet. Please wait and try again.'
                );

                return;
            }

            if ($response['success'] ?? false) {
                $description = $response['ResultDesc']
                    ?? 'M-PESA payment was not completed.';

                $transaction->update([
                    'status' => 'failed',
                    'description' => 'M-PESA payment failed: ' . $description,
                    'processed_at' => now(),
                ]);

                $this->addError(
                    'payment_method',
                    'M-PESA payment was not completed: ' . $description
                );

                $this->contribution->refresh();

                return;
            }

            $this->addError(
                'payment_method',
                'M-PESA could not confirm the payment yet. Please try again.'
            );
        } catch (\Throwable $e) {
            report($e);

            $this->addError(
                'payment_method',
                'We could not check the M-PESA payment status right now. Please try again.'
            );
        }
    }
    public function pay(): void
    {
        abort_unless(
            $this->canPayContribution(),
            403
        );

        $this->validate([
            'payment_method' => ['required', 'in:manual,mpesa,bank'],
            'payment_reference' => ['nullable', 'string', 'max:255'],
            'notes' => ['nullable', 'string', 'max:1000'],
        ]);

        if ($this->payment_method === 'mpesa') {
            $this->startMpesaPayment();

            return;
        }

        $reference = trim($this->payment_reference);

        if ($reference === '') {
            $reference = 'MANUAL-' . now()->format('YmdHis') . '-' . $this->contribution->id;
        }

        DB::transaction(function () use ($reference) {
            $contribution = Contribution::query()
                ->whereKey($this->contribution->id)
                ->lockForUpdate()
                ->firstOrFail();

            if ($contribution->status === 'paid') {
                throw new \RuntimeException(
                    'This contribution has already been marked as paid.'
                );
            }

            $contribution->load([
                'chama',
                'fund',
                'contributionPlan',
            ]);

            if (! $contribution->fund) {
                throw new \RuntimeException(
                    'This contribution is not assigned to a chama fund.'
                );
            }

            $contribution->update([
                'status' => 'paid',
                'paid_at' => now(),
                'payment_reference' => $reference,
                'payment_method' => $this->payment_method,
                'notes' => $this->notes ?: null,
            ]);

            Transaction::create([
                'chama_id' => $contribution->chama_id,
                'chama_fund_id' => $contribution->chama_fund_id,
                'user_id' => $contribution->user_id,
                'contribution_id' => $contribution->id,
                'type' => 'contribution',
                'amount' => $contribution->amount,
                'currency' => $contribution->fund->currency,
                'status' => 'completed',
                'payment_method' => $this->payment_method,
                'reference' => $reference,
                'external_reference' => null,
                'description' => 'Contribution payment',
                'processed_at' => now(),
            ]);
        });

        $this->contribution->refresh();

        session()->flash(
            'success',
            'Contribution paid successfully.'
        );

        $this->redirect(
            route('chamas.show', $this->contribution->chama->slug),
            navigate: true
        );
    }

    private function startMpesaPayment(): void
    {
        $payment = DB::transaction(function (): ?array {
            $contribution = Contribution::query()
                ->whereKey($this->contribution->id)
                ->lockForUpdate()
                ->firstOrFail();

            if ($contribution->status === 'paid') {
                throw new \RuntimeException(
                    'This contribution has already been marked as paid.'
                );
            }

            $contribution->load([
                'chama',
                'fund',
                'user',
            ]);

            if (! $contribution->fund) {
                throw new \RuntimeException(
                    'This contribution is not assigned to a chama fund.'
                );
            }

            $phoneNumber = trim((string) $contribution->user?->phone_number);

            if (config('mpesa.environment') === 'sandbox') {
                $phoneNumber = trim(
                    (string) config('mpesa.sandbox_phone_number', $phoneNumber)
                );
            }

            if ($phoneNumber === '') {
                throw new \RuntimeException(
                    'The contribution member does not have a phone number saved for M-PESA.'
                );
            }

            $existingPayment = Transaction::query()
                ->where('contribution_id', $contribution->id)
                ->where('payment_method', 'mpesa')
                ->where('status', 'pending')
                ->exists();

            if ($existingPayment) {
                return null;
            }

            $reference = 'MPESA-' . $contribution->id . '-' . now()->format('YmdHis');

            $transaction = Transaction::create([
                'chama_id' => $contribution->chama_id,
                'chama_fund_id' => $contribution->chama_fund_id,
                'user_id' => $contribution->user_id,
                'contribution_id' => $contribution->id,
                'type' => 'contribution',
                'amount' => $contribution->amount,
                'currency' => $contribution->fund->currency,
                'status' => 'pending',
                'payment_method' => 'mpesa',
                'reference' => $reference,
                'external_reference' => null,
                'gateway_reference' => null,
                'description' => 'M-PESA STK payment',
                'processed_at' => null,
            ]);

            return [
                'transaction_id' => $transaction->id,
                'phone_number' => $phoneNumber,
                'amount' => $contribution->amount,
                'account_reference' => 'CH' . $contribution->id,
            ];
        });

        if ($payment === null) {
            $this->addError(
                'payment_method',
                'An M-PESA payment request is already pending for this contribution. Please complete it before trying again.'
            );

            return;
        }

        try {
            $response = app(MpesaService::class)->stkPush(
                $payment['phone_number'],
                $payment['amount'],
                $payment['account_reference'],
                'Chama payment'
            );

            Transaction::query()
                ->whereKey($payment['transaction_id'])
                ->update([
                    'gateway_reference' => $response['CheckoutRequestID'],
                ]);
        } catch (\Throwable $exception) {
            Transaction::query()
                ->whereKey($payment['transaction_id'])
                ->update([
                    'status' => 'failed',
                    'description' => 'M-PESA STK request failed: ' . $exception->getMessage(),
                    'processed_at' => now(),
                ]);

            $this->addError(
                'payment_method',
                $exception->getMessage()
            );

            return;
        }

        session()->flash(
            'success',
            'M-PESA payment request sent. Check the configured sandbox/test phone and complete the prompt.'
        );

        $this->redirect(
            route('chamas.show', $this->contribution->chama->slug),
            navigate: true
        );
    }
};
?>

<div class="mx-auto max-w-3xl space-y-6">
    <div>
        <a
            href="{{ route('chamas.show', $contribution->chama->slug) }}"
            wire:navigate
            class="inline-flex items-center gap-2 text-sm font-medium text-indigo-600 transition hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300"
        >
            <span aria-hidden="true">&larr;</span>
            Back to {{ $contribution->chama->name }}
        </a>

    <div class="mt-4">
        <div class="flex flex-wrap items-center gap-2">
            <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">
                {{ $contribution->chama->name }}
            </p>

            @if ($this->isPaid())
                <flux:badge color="green">
                    Paid
                </flux:badge>
            @elseif ($this->hasPendingMpesaPayment())
                <flux:badge color="blue">
                    M-PESA Pending
                </flux:badge>
            @elseif ($contribution->due_date && $contribution->due_date->isBefore(today()))
                <flux:badge color="red">
                    Overdue
                </flux:badge>
            @else
                <flux:badge color="yellow">
                    Pending
                </flux:badge>
            @endif
        </div>

        <h1 class="mt-1 text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
            {{ $this->isPaid() ? 'Contribution Payment Record' : 'Pay Contribution' }}
        </h1>

        <p class="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
            {{ $contribution->contributionPlan?->name ?? 'Contribution' }}
        </p>
    </div>
</div>

@if ($this->isPaid())
    <div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-5 dark:border-emerald-900/50 dark:bg-emerald-950/30">
        <div class="flex items-start gap-3">
            <div>
                <h2 class="font-semibold text-emerald-900 dark:text-emerald-200">
                    Contribution already paid
                </h2>

                <p class="mt-1 text-sm leading-6 text-emerald-800 dark:text-emerald-300">
                    This contribution has already been recorded as paid. No additional payment is required.
                </p>
            </div>
        </div>
    </div>
@elseif ($this->hasPendingMpesaPayment())
    @php($pendingMpesa = $this->pendingMpesaTransaction())

    <div class="rounded-2xl border border-blue-200 bg-blue-50 p-5 dark:border-blue-900/50 dark:bg-blue-950/30">
        <div class="flex flex-col gap-5 sm:flex-row sm:items-start sm:justify-between">
            <div>
                <h2 class="font-semibold text-blue-900 dark:text-blue-200">
                    M-PESA payment pending
                </h2>

                <p class="mt-1 text-sm leading-6 text-blue-800 dark:text-blue-300">
                    An M-PESA payment request has already been sent. Complete the prompt on the configured phone, then check the payment status below.
                </p>

                @if ($pendingMpesa?->gateway_reference)
                    <p class="mt-3 break-all text-xs text-blue-700 dark:text-blue-300">
                        Checkout Request:
                        <span class="font-mono font-semibold">
                            {{ $pendingMpesa->gateway_reference }}
                        </span>
                    </p>
                @endif
            </div>

            <button
                type="button"
                wire:click="refreshMpesaStatus"
                wire:loading.attr="disabled"
                class="inline-flex shrink-0 items-center justify-center rounded-xl bg-blue-600 px-5 py-3 text-sm font-semibold text-white shadow-sm transition hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
            >
                <span wire:loading.remove wire:target="refreshMpesaStatus">
                    Check Payment Status
                </span>

                <span wire:loading wire:target="refreshMpesaStatus">
                    Checking...
                </span>
            </button>
        </div>
    </div>
@endif

@if ($errors->has('payment_method'))
    <div class="rounded-2xl border border-red-200 bg-red-50 p-4 dark:border-red-900/50 dark:bg-red-950/30">
        <p class="text-sm font-medium text-red-800 dark:text-red-300">
            {{ $errors->first('payment_method') }}
        </p>
    </div>
@endif

<div class="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
    <div class="border-b border-zinc-200 px-6 py-5 dark:border-zinc-700">
        <p class="text-sm font-medium text-zinc-500 dark:text-zinc-400">
            Contribution amount
        </p>

        <div class="mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-1">
            <span class="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">
                {{ $contribution->fund?->currency ?? $contribution->chama->currency }}
                {{ number_format($contribution->amount, 2) }}
            </span>

            <span class="text-sm text-zinc-500 dark:text-zinc-400">
                {{ $contribution->contributionPlan?->frequency ?? 'scheduled' }}
            </span>
        </div>
    </div>

    <div class="grid gap-px bg-zinc-200 sm:grid-cols-2 dark:bg-zinc-700">
        <div class="bg-white p-5 dark:bg-zinc-900">
            <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                Due Date
            </p>

            <p class="mt-1 font-semibold text-zinc-900 dark:text-white">
                {{ $contribution->due_date->format('d M Y') }}
            </p>
        </div>

        <div class="bg-white p-5 dark:bg-zinc-900">
            <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                Fund
            </p>

            <p class="mt-1 font-semibold text-zinc-900 dark:text-white">
                {{ $contribution->fund?->name ?? 'Not assigned' }}
            </p>
        </div>

        @if ($this->isPaid())
            <div class="bg-white p-5 dark:bg-zinc-900">
                <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:bg-zinc-900">
                    Paid At
                </p>

                <p class="mt-1 font-semibold text-zinc-900 dark:text-white">
                    {{ $contribution->paid_at?->format('d M Y, H:i') ?? '' }}
                </p>
            </div>

            <div class="bg-white p-5 dark:bg-zinc-900">
                <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                    Payment Method
                </p>

                <p class="mt-1 font-semibold capitalize text-zinc-900 dark:text-white">
                    {{ $contribution->payment_method ?? '' }}
                </p>
            </div>

            <div class="bg-white p-5 sm:col-span-2 dark:bg-zinc-900">
                <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                    Payment Reference
                </p>

                <p class="mt-1 break-all font-mono text-sm font-semibold text-zinc-900 dark:text-white">
                    {{ $contribution->payment_reference ?? '' }}
                </p>
            </div>

            @if ($contribution->notes)
                <div class="bg-white p-5 sm:col-span-2 dark:bg-zinc-900">
                    <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                        Payment Notes
                    </p>

                    <p class="mt-1 text-sm leading-6 text-zinc-700 dark:text-zinc-300">
                        {{ $contribution->notes }}
                    </p>
                </div>
            @endif
        @endif
    </div>
</div>

@if (! $this->isPaid() && ! $this->hasPendingMpesaPayment())
    <form wire:submit="pay" class="space-y-5">
        <div class="rounded-2xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
            <div>
                <h2 class="text-lg font-semibold text-zinc-900 dark:text-white">
                    Payment Details
                </h2>

                <p class="mt-1 text-sm leading-6 text-zinc-500 dark:text-zinc-400">
                    Record how this contribution was paid. The payment will be added to the selected fund and transaction ledger.
                </p>
            </div>

            <div class="mt-6 space-y-5">
                <div>
                    <label
                        for="payment_method"
                        class="mb-2 block text-sm font-medium text-zinc-700 dark:text-zinc-300"
                    >
                        Payment Method
                    </label>

                    <select
                        id="payment_method"
                        wire:model="payment_method"
                        class="w-full rounded-xl border-zinc-300 bg-white px-3 py-2.5 text-sm text-zinc-900 focus:border-indigo-500 focus:ring-indigo-500 dark:border-zinc-600 dark:bg-zinc-800 dark:text-white"
                    >
                        <option value="manual">Manual / Cash</option>
                        <option value="mpesa">M-PESA</option>
                        <option value="bank">Bank Transfer</option>
                    </select>

                    @error('payment_method')
                        <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
                    @enderror
                </div>

                <div>
                    <label
                        for="payment_reference"
                        class="mb-2 block text-sm font-medium text-zinc-700 dark:text-zinc-300"
                    >
                        Payment Reference
                    </label>

                    <input
                        id="payment_reference"
                        type="text"
                        wire:model="payment_reference"
                        placeholder="e.g. M-PESA transaction code"
                        class="w-full rounded-xl border-zinc-300 bg-white px-3 py-2.5 text-sm text-zinc-900 placeholder:text-zinc-400 focus:border-indigo-500 focus:ring-indigo-500 dark:border-zinc-600 dark:bg-zinc-800 dark:text-white dark:placeholder:text-zinc-500"
                    >

                    <p class="mt-2 text-xs leading-5 text-zinc-500 dark:text-zinc-400">
                        Leave blank to generate a reference automatically.
                    </p>

                    @error('payment_reference')
                        <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
                    @enderror
                </div>

                <div>
                    <label
                        for="notes"
                        class="mb-2 block text-sm font-medium text-zinc-700 dark:text-zinc-300"
                    >
                        Notes
                    </label>

                    <textarea
                        id="notes"
                        wire:model="notes"
                        rows="4"
                        placeholder="Optional payment notes"
                        class="w-full rounded-xl border-zinc-300 bg-white px-3 py-2.5 text-sm text-zinc-900 placeholder:text-zinc-400 focus:border-indigo-500 focus:ring-indigo-500 dark:border-zinc-600 dark:bg-zinc-800 dark:text-white"
                    ></textarea>

                    @error('notes')
                        <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>
                    @enderror
                </div>
            </div>
        </div>

        <div class="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end">
            <a
                href="{{ route('chamas.show', $contribution->chama->slug) }}"
                class="inline-flex items-center justify-center rounded-xl border border-zinc-300 px-5 py-3 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 dark:border-zinc-600 dark:text-zinc-200 dark:hover:bg-zinc-800"
            >
                Cancel
            </a>

            <button
                type="submit"
                wire:loading.attr="disabled"
                class="inline-flex items-center justify-center rounded-xl bg-indigo-600 px-5 py-3 text-sm font-semibold text-white shadow-sm transition hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50"
            >
                <span wire:loading.remove>
                    Pay Contribution
                </span>

                <span wire:loading>
                    Processing...
                </span>
            </button>
        </div>
    </form>
@elseif ($this->isPaid())
    <div class="flex flex-col gap-3 sm:flex-row sm:justify-end">
        <a
            href="{{ route('contributions.history', $contribution->chama->slug) }}"
            wire:navigate
            class="inline-flex items-center justify-center rounded-xl border border-zinc-300 px-5 py-3 text-sm font-semibold text-zinc-700 transition hover:bg-zinc-50 dark:border-zinc-600 dark:text-zinc-200 dark:hover:bg-zinc-800"
        >
            View Contribution History
        </a>

        <a
            href="{{ route('chamas.show', $contribution->chama->slug) }}"
            wire:navigate
            class="inline-flex items-center justify-center rounded-xl bg-indigo-600 px-5 py-3 text-sm font-semibold text-white transition hover:bg-indigo-700"
        >
            Back to Chama
        </a>
    </div>
@endif

</div>

