<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\Models\OwnerTransaction;
use App\Models\UserAccount;
use App\Services\AccountService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;

class OwnerTransactionController extends Controller
{
    private function getTransaction($trx)
    {
        return OwnerTransaction::where('user_id', auth()->id())
            ->findOrFail($trx->id ?? $trx);
    }

    public function index(Request $request)
    {
        $base = OwnerTransaction::query()
            ->where('user_id', auth()->id())
            ->with(['account:id,name,type']);

        if ($request->filled('type')) {
            $base->where('type', $request->type);
        }

        if ($request->filled('user_account_id')) {
            $base->where('user_account_id', (int) $request->user_account_id);
        }

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

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

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

        if ($request->filled('search')) {
            $s = trim($request->search);

            $base->where(function ($q) use ($s) {
                $q->where('trx_no', 'like', "%{$s}%")
                    ->orWhere('note', 'like', "%{$s}%");
            });
        }

        $rows = (clone $base)
            ->orderByDesc('posted_at')
            ->orderByDesc('id')
            ->paginate(20)
            ->withQueryString();

        $sumInvestment = (float) (clone $base)->where('type', 'investment')->sum('amount');
        $sumDrawing = (float) (clone $base)->where('type', 'drawing')->sum('amount');
        $netOwner = round($sumInvestment - $sumDrawing, 2);

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

        return view('user.owner_transactions.index', compact(
            'rows',
            'accounts',
            'sumInvestment',
            'sumDrawing',
            'netOwner'
        ));
    }

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

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

    public function store(Request $request)
    {
        $data = $request->validate([
            'type'            => ['required', 'in:investment,drawing'],
            'user_account_id' => ['required', 'integer'],
            'amount'          => ['required', 'numeric', 'min:0.01'],
            'note'            => ['nullable', 'string', 'max:2000'],
            'posted_at'       => ['nullable', 'date', 'before_or_equal:now'],
        ], [
            'type.required'             => __('Owner_Transaction_Controller.validation.type_required'),
            'type.in'                   => __('Owner_Transaction_Controller.validation.type_in'),
            'user_account_id.required'  => __('Owner_Transaction_Controller.validation.user_account_id_required'),
            'user_account_id.integer'   => __('Owner_Transaction_Controller.validation.user_account_id_integer'),
            'amount.required'           => __('Owner_Transaction_Controller.validation.amount_required'),
            'amount.numeric'            => __('Owner_Transaction_Controller.validation.amount_numeric'),
            'amount.min'                => __('Owner_Transaction_Controller.validation.amount_min'),
            'note.string'               => __('Owner_Transaction_Controller.validation.note_string'),
            'note.max'                  => __('Owner_Transaction_Controller.validation.note_max'),
            'posted_at.date'            => __('Owner_Transaction_Controller.validation.posted_at_date'),
            'posted_at.before_or_equal' => __('Owner_Transaction_Controller.validation.posted_at_before_or_equal'),
        ]);

        $account = UserAccount::where('id', (int) $data['user_account_id'])
            ->where('user_id', auth()->id())
            ->where('status', 'active')
            ->firstOrFail();

        $postedAt = $data['posted_at'] ?? now();
        $trxNo = 'OWN-' . now()->format('ymdHis') . '-' . random_int(100, 999);

        try {
            DB::transaction(function () use ($data, $account, $postedAt, $trxNo) {

                $row = OwnerTransaction::create([
                    'user_id'         => auth()->id(),
                    'user_account_id' => $account->id,
                    'type'            => $data['type'],
                    'trx_no'          => $trxNo,
                    'amount'          => (float) $data['amount'],
                    'note'            => $data['note'] ?? null,
                    'posted_at'       => $postedAt,
                ]);

                $debit = $row->type === 'investment' ? (float) $row->amount : 0;
                $credit = $row->type === 'drawing' ? (float) $row->amount : 0;

                AccountService::upsertLedgerByReference(
                    auth()->id(),
                    OwnerTransaction::class,
                    $row->id,
                    $account->id,
                    $row->type,
                    $trxNo,
                    $debit,
                    $credit,
                    $row->note ?: __(
                        $row->type === 'investment'
                            ? 'Owner_Transaction_Controller.messages.owner_investment'
                            : 'Owner_Transaction_Controller.messages.owner_drawing'
                    ),
                    $postedAt
                );
            });

            return redirect()
                ->route('user.owner_transactions.index')
                ->with('ok', __('Owner_Transaction_Controller.messages.store_success'));

        } catch (Throwable $e) {
            return back()
                ->withInput()
                ->with('err', __('Owner_Transaction_Controller.messages.store_failed'));
        }
    }

    public function edit($id)
    {
        $ownerTransaction = $this->getTransaction($id);

        $accounts = UserAccount::where('user_id', auth()->id())
            ->where('status', 'active')
            ->orderBy('name')
            ->get(['id', 'name', 'type']);

        return view('user.owner_transactions.edit', [
            'row' => $ownerTransaction,
            'accounts' => $accounts,
        ]);
    }

    public function update(Request $request, $id)
    {
        $ownerTransaction = $this->getTransaction($id);

        $data = $request->validate([
            'type'            => ['required', 'in:investment,drawing'],
            'user_account_id' => ['required', 'integer'],
            'amount'          => ['required', 'numeric', 'min:0.01'],
            'note'            => ['nullable', 'string', 'max:2000'],
            'posted_at'       => ['nullable', 'date', 'before_or_equal:now'],
        ], [
            'type.required'             => __('Owner_Transaction_Controller.validation.type_required'),
            'type.in'                   => __('Owner_Transaction_Controller.validation.type_in'),
            'user_account_id.required'  => __('Owner_Transaction_Controller.validation.user_account_id_required'),
            'user_account_id.integer'   => __('Owner_Transaction_Controller.validation.user_account_id_integer'),
            'amount.required'           => __('Owner_Transaction_Controller.validation.amount_required'),
            'amount.numeric'            => __('Owner_Transaction_Controller.validation.amount_numeric'),
            'amount.min'                => __('Owner_Transaction_Controller.validation.amount_min'),
            'note.string'               => __('Owner_Transaction_Controller.validation.note_string'),
            'note.max'                  => __('Owner_Transaction_Controller.validation.note_max'),
            'posted_at.date'            => __('Owner_Transaction_Controller.validation.posted_at_date'),
            'posted_at.before_or_equal' => __('Owner_Transaction_Controller.validation.posted_at_before_or_equal'),
        ]);

        $account = UserAccount::where('id', (int) $data['user_account_id'])
            ->where('user_id', auth()->id())
            ->where('status', 'active')
            ->firstOrFail();

        $postedAt = $data['posted_at'] ?? ($ownerTransaction->posted_at ?? now());
        $trxNo = $ownerTransaction->trx_no ?: ('OWN-' . now()->format('ymdHis') . '-' . random_int(100, 999));

        try {
            DB::transaction(function () use ($ownerTransaction, $data, $account, $postedAt, $trxNo) {

                $ownerTransaction->update([
                    'type'            => $data['type'],
                    'user_account_id' => $account->id,
                    'amount'          => (float) $data['amount'],
                    'note'            => $data['note'] ?? null,
                    'posted_at'       => $postedAt,
                    'trx_no'          => $trxNo,
                ]);

                $debit = $ownerTransaction->type === 'investment' ? (float) $ownerTransaction->amount : 0;
                $credit = $ownerTransaction->type === 'drawing' ? (float) $ownerTransaction->amount : 0;

                AccountService::upsertLedgerByReference(
                    auth()->id(),
                    OwnerTransaction::class,
                    $ownerTransaction->id,
                    $account->id,
                    $ownerTransaction->type,
                    $trxNo,
                    $debit,
                    $credit,
                    $ownerTransaction->note ?: __(
                        $ownerTransaction->type === 'investment'
                            ? 'Owner_Transaction_Controller.messages.owner_investment'
                            : 'Owner_Transaction_Controller.messages.owner_drawing'
                    ),
                    $postedAt
                );
            });

            return redirect()
                ->route('user.owner_transactions.index')
                ->with('ok', __('Owner_Transaction_Controller.messages.update_success'));

        } catch (Throwable $e) {
            return back()
                ->withInput()
                ->with('err', __('Owner_Transaction_Controller.messages.update_failed'));
        }
    }

    public function destroy($id)
    {
        $ownerTransaction = $this->getTransaction($id);

        try {
            DB::transaction(function () use ($ownerTransaction) {

                AccountService::deleteLedgerByReference(
                    auth()->id(),
                    OwnerTransaction::class,
                    $ownerTransaction->id
                );

                $ownerTransaction->delete();
            });

            return redirect()
                ->route('user.owner_transactions.index')
                ->with('ok', __('Owner_Transaction_Controller.messages.destroy_success'));

        } catch (Throwable $e) {
            return redirect()
                ->route('user.owner_transactions.index')
                ->with('err', __('Owner_Transaction_Controller.messages.destroy_failed'));
        }
    }
}