<?php

namespace App\Http\Controllers\Tenant;

use App\Http\Controllers\Controller;
use App\Models\MemberTransfer;
use App\Models\User;
use App\Services\MemberTransferService;
use App\Services\TransactionApprovalSettings;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\View\View;
use InvalidArgumentException;

class MemberTransferController extends Controller
{
    public function index(Request $request): View
    {
        $user = $request->user();
        $staffRoles = [User::ROLE_TENANT_ADMIN, User::ROLE_MANAGER, User::ROLE_LOAN_OFFICER, User::ROLE_ACCOUNTANT];
        $approvalRequired = app(TransactionApprovalSettings::class)->requiresApproval($user->tenant, 'transfer');

        $validated = $request->validate([
            'q' => ['nullable', 'string', 'max:255'],
            'transfer_type' => ['nullable', Rule::in([MemberTransfer::TYPE_INTERNAL, MemberTransfer::TYPE_BANK])],
            'status' => ['nullable', Rule::in([MemberTransfer::STATUS_POSTED, MemberTransfer::STATUS_REJECTED, MemberTransfer::STATUS_CANCELED, MemberTransfer::STATUS_FAILED])],
            'initiated_by' => ['nullable', 'integer'],
            'approved_by' => ['nullable', 'integer'],
            'from' => ['nullable', 'date'],
            'to' => ['nullable', 'date', 'after_or_equal:from'],
        ]);

        $search = trim((string) ($validated['q'] ?? ''));
        $transferType = $validated['transfer_type'] ?? null;
        $status = $validated['status'] ?? null;
        $initiatedBy = $validated['initiated_by'] ?? null;
        $approvedBy = $validated['approved_by'] ?? null;
        $from = $validated['from'] ?? null;
        $to = $validated['to'] ?? null;

        $base = MemberTransfer::with([
                'sender',
                'sourceAccount',
                'recipient',
                'recipientAccount',
                'initiator',
                'approver',
                'rejecter',
                'canceler',
            ])
            ->whereHas('sender', fn ($query) => $query->visibleTo($user));

        $pendingTransfers = (clone $base)
            ->where('status', MemberTransfer::STATUS_PENDING)
            ->latest()
            ->get();

        $historyQuery = (clone $base)
            ->whereIn('status', [MemberTransfer::STATUS_POSTED, MemberTransfer::STATUS_REJECTED, MemberTransfer::STATUS_CANCELED, MemberTransfer::STATUS_FAILED])
            ->when($search !== '', function ($query) use ($search): void {
                $like = '%'.str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $search).'%';

                $query->where(function ($inner) use ($like): void {
                    $inner->where('reference', 'like', $like)
                        ->orWhere('recipient_account_number', 'like', $like)
                        ->orWhere('recipient_account_name', 'like', $like)
                        ->orWhere('recipient_bank_name', 'like', $like)
                        ->orWhere('narration', 'like', $like)
                        ->orWhereHas('sender', function ($sender) use ($like): void {
                            $sender->where('first_name', 'like', $like)
                                ->orWhere('middle_name', 'like', $like)
                                ->orWhere('last_name', 'like', $like)
                                ->orWhere('account_number', 'like', $like)
                                ->orWhere('phone', 'like', $like);
                        })
                        ->orWhereHas('sourceAccount', fn ($account) => $account->where('account_number', 'like', $like));
                });
            })
            ->when($transferType, fn ($query) => $query->where('transfer_type', $transferType))
            ->when($status, fn ($query) => $query->where('status', $status))
            ->when($initiatedBy, fn ($query) => $query->where('initiated_by', $initiatedBy))
            ->when($approvedBy, fn ($query) => $query->where('approved_by', $approvedBy))
            ->when($from, fn ($query) => $query->whereDate('created_at', '>=', $from))
            ->when($to, fn ($query) => $query->whereDate('created_at', '<=', $to));

        $postedBase = (clone $base)->where('status', MemberTransfer::STATUS_POSTED);

        return view('tenant.transfers.index', [
            'pendingTransfers' => $pendingTransfers,
            'transferApprovalRequired' => $approvalRequired,
            'transfers' => $historyQuery->latest()->paginate(15)->withQueryString(),
            'transferStats' => [
                'today_amount' => (clone $postedBase)->whereDate('posted_at', today())->sum('total_amount'),
                'today_count' => (clone $postedBase)->whereDate('posted_at', today())->count(),
                'pending_amount' => $pendingTransfers->sum('total_amount'),
                'pending_count' => $pendingTransfers->count(),
                'bank_pending_amount' => $pendingTransfers->where('transfer_type', MemberTransfer::TYPE_BANK)->sum('total_amount'),
                'bank_pending_count' => $pendingTransfers->where('transfer_type', MemberTransfer::TYPE_BANK)->count(),
                'month_amount' => (clone $postedBase)->whereBetween('posted_at', [now()->startOfMonth(), now()->endOfMonth()])->sum('total_amount'),
                'month_count' => (clone $postedBase)->whereBetween('posted_at', [now()->startOfMonth(), now()->endOfMonth()])->count(),
            ],
            'search' => $search,
            'transferType' => $transferType,
            'status' => $status,
            'initiatedBy' => $initiatedBy,
            'approvedBy' => $approvedBy,
            'usersForFilter' => User::query()
                ->where('tenant_id', $user->tenant_id)
                ->whereIn('role', $staffRoles)
                ->orderBy('name')
                ->get(['id', 'name']),
            'from' => $from,
            'to' => $to,
        ]);
    }

    public function approve(Request $request, MemberTransfer $transfer, MemberTransferService $transfers): RedirectResponse
    {
        abort_unless($transfer->sender?->isVisibleTo($request->user()) ?? false, 403);

        try {
            $posted = $transfers->approve($transfer, $request->user()->id);
        } catch (InvalidArgumentException $exception) {
            return back()->with('warning', $exception->getMessage());
        }

        return back()->with('status', 'Transfer '.$posted->reference.' approved and posted.');
    }

    public function reject(Request $request, MemberTransfer $transfer, MemberTransferService $transfers): RedirectResponse
    {
        abort_unless($transfer->sender?->isVisibleTo($request->user()) ?? false, 403);

        $validated = $request->validate([
            'reason' => ['nullable', 'string', 'max:1000'],
        ]);

        try {
            $transfers->reject($transfer, $request->user()->id, $validated['reason'] ?? null);
        } catch (InvalidArgumentException $exception) {
            return back()->with('warning', $exception->getMessage());
        }

        return back()->with('status', 'Transfer rejected.');
    }

    public function cancel(Request $request, MemberTransfer $transfer, MemberTransferService $transfers): RedirectResponse
    {
        abort_unless($transfer->sender?->isVisibleTo($request->user()) ?? false, 403);

        $validated = $request->validate([
            'reason' => ['nullable', 'string', 'max:1000'],
        ]);

        try {
            $transfers->cancel($transfer, $request->user()->id, $validated['reason'] ?? null);
        } catch (InvalidArgumentException $exception) {
            return back()->with('warning', $exception->getMessage());
        }

        return back()->with('status', 'Transfer canceled.');
    }
}
