<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\Models\AccountLedger;
use App\Models\AccountTransfer;
use App\Models\UserAccount;
use App\Services\LedgerService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class AccountTransferController extends Controller
{
    public function index(Request $request)
    {
        $q = AccountTransfer::where('user_id', auth()->id())
            ->with(['fromAccount', 'toAccount']);

        if ($request->filled('from_account_id')) {
            $q->where('from_account_id', $request->from_account_id);
        }

        if ($request->filled('to_account_id')) {
            $q->where('to_account_id', $request->to_account_id);
        }

        if ($request->filled('date')) {
            $q->whereDate('posted_at', $request->date);
        }

        if ($request->filled('month')) {
            $q->whereMonth('posted_at', (int) $request->month);
        }

        if ($request->filled('year')) {
            $q->whereYear('posted_at', (int) $request->year);
        }

        $transfers = $q->latest('posted_at')
            ->latest()
            ->paginate(15)
            ->withQueryString();

        $accounts = UserAccount::where('user_id', auth()->id())
            ->orderBy('name')
            ->get();

        return view('user.account_transfers.index', compact('transfers', 'accounts'));
    }

    public function create()
    {
        $accounts = UserAccount::where('user_id', auth()->id())
            ->where('status', 'active')
            ->orderBy('name')
            ->get();

        return view('user.account_transfers.create', compact('accounts'));
    }

    public function store(Request $request, LedgerService $ledger)
    {
        $data = $request->validate([
            'from_account_id' => ['required', 'exists:user_accounts,id'],
            'to_account_id'   => ['required', 'exists:user_accounts,id', 'different:from_account_id'],
            'amount'          => ['required', 'numeric', 'min:0.01'],
            'bank_charge'     => ['nullable', 'numeric', 'min:0'],
            'note'            => ['nullable', 'string', 'max:2000'],
            'posted_at'       => ['nullable', 'date', 'before_or_equal:now'],
        ]);

        $from = UserAccount::where('id', $data['from_account_id'])
            ->where('user_id', auth()->id())
            ->firstOrFail();

        $to = UserAccount::where('id', $data['to_account_id'])
            ->where('user_id', auth()->id())
            ->firstOrFail();

        DB::transaction(function () use ($data, $from, $to, $ledger) {
            $trxNo = $ledger->trxNo();
            $postedAt = $data['posted_at'] ?? now();

            $transfer = AccountTransfer::create([
                'user_id'         => auth()->id(),
                'from_account_id' => $from->id,
                'to_account_id'   => $to->id,
                'amount'          => $data['amount'],
                'bank_charge'     => $data['bank_charge'] ?? 0,
                'note'            => $data['note'] ?? null,
                'trx_no'          => $trxNo,
                'posted_at'       => $postedAt,
            ]);

            AccountLedger::updateOrCreate(
                [
                    'reference_type'  => AccountTransfer::class,
                    'reference_id'    => $transfer->id,
                    'user_account_id' => $from->id,
                    'type'            => 'transfer_out',
                ],
                [
                    'user_id'     => auth()->id(),
                    'trx_no'      => $trxNo,
                    'posted_at'   => $postedAt,
                    'debit'       => 0,
                    'credit'      => (float) $data['amount'],
                    'description' => __('Account_Transfer_Controller.messages.transfer_out_to') . $to->name,
                ]
            );

            AccountLedger::updateOrCreate(
                [
                    'reference_type'  => AccountTransfer::class,
                    'reference_id'    => $transfer->id,
                    'user_account_id' => $to->id,
                    'type'            => 'transfer_in',
                ],
                [
                    'user_id'     => auth()->id(),
                    'trx_no'      => $trxNo,
                    'posted_at'   => $postedAt,
                    'debit'       => (float) $data['amount'],
                    'credit'      => 0,
                    'description' => __('Account_Transfer_Controller.messages.transfer_in_from') . $from->name,
                ]
            );

            $charge = (float) ($data['bank_charge'] ?? 0);
            if ($charge > 0) {
                AccountLedger::updateOrCreate(
                    [
                        'reference_type'  => AccountTransfer::class,
                        'reference_id'    => $transfer->id,
                        'user_account_id' => $from->id,
                        'type'            => 'bank_charge',
                    ],
                    [
                        'user_id'     => auth()->id(),
                        'trx_no'      => $trxNo,
                        'posted_at'   => $postedAt,
                        'debit'       => 0,
                        'credit'      => $charge,
                        'description' => __('Account_Transfer_Controller.messages.bank_charge_for_transfer'),
                    ]
                );
            }
        });

        return redirect()
            ->route('user.account_transfers.index')
            ->with('ok', __('Account_Transfer_Controller.messages.transfer_completed'));
    }

    public function destroy($id)
    {
        $transfer = AccountTransfer::where('user_id', auth()->id())
            ->findOrFail($id);

        DB::transaction(function () use ($transfer) {
            AccountLedger::where('reference_type', AccountTransfer::class)
                ->where('reference_id', $transfer->id)
                ->delete();

            $transfer->delete();
        });

        return redirect()
            ->route('user.account_transfers.index')
            ->with('ok', __('Account_Transfer_Controller.messages.transfer_deleted'));
    }
}