<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use App\Models\Customer;
use App\Models\Order;
use Brian2694\Toastr\Facades\Toastr;
use App\CPU\Helpers;
use App\Models\Account;
use App\Models\Transection;
use function App\CPU\translate;
use App\Traits\TransactionTrait;

class CustomerController extends Controller
{
    use TransactionTrait;

    public function __construct(
        private Customer    $customer,
        private Order       $order,
        private Account     $account,
        private Transection $transection
    )
    {
    }

    /**
     * @return Application|Factory|View
     */
    public function index(): View|Factory|Application
    {
        return view('admin-views.customer.index');
    }

    /**
     * @param Request $request
     * @return RedirectResponse
     */
    public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'name' => 'required',
            'mobile' => 'required|unique:customers',
            'image' => 'image|mimes:jpeg,png,jpg,gif|max:2048'
        ]);

        if (!empty($request->file('image'))) {
            $imageName = Helpers::upload('customer/', 'png', $request->file('image'));
        } else {
            $imageName = 'def.png';
        }

        $customer = $this->customer;
        $customer->name = $request->name;
        $customer->mobile = $request->mobile;
        $customer->email = $request->email;
        $customer->image = $imageName;
        $customer->state = $request->state;
        $customer->city = $request->city;
        $customer->zip_code = $request->zip_code;
        $customer->address = $request->address;
        $customer->balance = $request->balance;
        $customer->save();

        Toastr::success(translate('Customer Added successfully'));
        return back();
    }

    /**
     * @param Request $request
     * @return Application|Factory|View
     */
    public function list(Request $request): View|Factory|Application
    {
        $accounts = $this->account->orderBy('id')->get();
        $queryParam = [];
        $search = $request['search'];
        if ($request->has('search')) {
            $key = explode(' ', $request['search']);
            $customers = $this->customer->where(function ($q) use ($key) {
                foreach ($key as $value) {
                    $q->orWhere('name', 'like', "%{$value}%")
                        ->orWhere('mobile', 'like', "%{$value}%");
                }
            });

            $queryParam = ['search' => $request['search']];
        } else {
            $customers = $this->customer;
        }

        $customers = $customers->where('id', '!=', '0')->latest('id')->paginate(Helpers::pagination_limit())->appends($queryParam);
        $walkingCustomer = $this->customer->where('id', '=', '0')->first();
        return view('admin-views.customer.list', compact('customers', 'accounts', 'search', 'walkingCustomer'));
    }

    /**
     * @param Request $request
     * @param $id
     * @return Application|Factory|View|RedirectResponse
     */
    public function view(Request $request, $id): View|Factory|RedirectResponse|Application
    {
        $customer = $this->customer->where('id', $id)->first();
        if (isset($customer)) {
            $queryParam = [];
            $search = $request['search'];
            if ($request->has('search')) {
                $key = explode(' ', $request['search']);
                $orders = $this->order->where(['user_id' => $id])
                    ->where(function ($q) use ($key) {
                        foreach ($key as $value) {
                            $q->where('id', 'like', "%{$value}%");
                        }
                    });
                $queryParam = ['search' => $request['search']];
            } else {
                $orders = $this->order->where(['user_id' => $id]);
            }

            $orders = $orders->latest()->paginate(Helpers::pagination_limit())->appends($queryParam);
            return view('admin-views.customer.view', compact('customer', 'orders', 'search'));
        }

        Toastr::error('Customer not found!');
        return back();
    }

    /**
     * @param Request $request
     * @param $id
     * @return Application|Factory|View|RedirectResponse
     */
    public function transactionList(Request $request, $id): View|Factory|RedirectResponse|Application
    {
        $accounts = $this->account->get();
        $customer = $this->customer->where('id', $id)->first();
        if (isset($customer)) {
            $accId = $request['account_id'];
            $tran_type = $request['tran_type'];
            $orders = $this->order->where(['user_id' => $id])->get();
            $transactions = $this->transection->where(['customer_id' => $id])
                ->when($accId != null, function ($q) use ($request) {
                    return $q->where('account_id', $request['account_id']);
                })
                ->when($tran_type != null, function ($q) use ($request) {
                    return $q->where('tran_type', $request['tran_type']);
                })->latest()->paginate(Helpers::pagination_limit())
                ->appends(['account_id' => $request['account_id'], 'tran_type' => $request['tran_type']]);
            return view('admin-views.customer.transaction-list', compact('customer', 'transactions', 'orders', 'tran_type', 'accounts', 'accId'));
        }

        Toastr::error(translate('Customer not found'));
        return back();
    }

    /**
     * @param Request $request
     * @return Application|Factory|View
     */
    public function edit(Request $request): Factory|View|Application
    {
        $customer = $this->customer->where('id', $request->id)->first();
        return view('admin-views.customer.edit', compact('customer'));
    }

    /**
     * @param Request $request
     * @return RedirectResponse
     */
    public function update(Request $request): RedirectResponse
    {
        $customer = $this->customer->where('id', $request->id)->first();

        $request->validate([
            'name' => 'required',
            'mobile' => 'required|unique:customers,mobile,' . $customer->id,
            'image' => 'image|mimes:jpeg,png,jpg,gif|max:2048'
        ]);

        $customer->name = $request->name;
        $customer->mobile = $request->mobile;
        $customer->email = $request->email;
        $customer->image = $request->has('image') ? Helpers::update('customer/', $customer->image, 'png', $request->file('image')) : $customer->image;
        $customer->state = $request->state;
        $customer->city = $request->city;
        $customer->zip_code = $request->zip_code;
        $customer->address = $request->address;
        $customer->balance = $request->balance;
        $customer->save();

        Toastr::success(translate('Customer updated successfully'));
        return back();
    }

    /**
     * @param Request $request
     * @return RedirectResponse
     */
    public function delete(Request $request): RedirectResponse
    {
        $customer = $this->customer->find($request->id);
        Helpers::delete('customer/' . $customer['image']);
        $customer->delete();

        Toastr::success(translate('Customer removed successfully'));
        return back();
    }

    /**
     * @param Request $request
     * @return RedirectResponse
     */
    public function updateBalance(Request $request): RedirectResponse
    {
        $request->validate([
            'customer_id' => 'required',
            'amount' => 'required',
            'account_id' => 'required',
            'date' => 'required',
        ]);

        $customer = $this->customer->find($request->customer_id);
        $amount = $request->amount;
        $remainingBalance = $customer->balance + $amount;

        \DB::transaction(function () use ($customer, $request, $amount, $remainingBalance) {
            // Handle receiving account transaction
            $receiveAccount = Account::find($request->account_id);
            $this->createTransaction(
                'Income',
                $receiveAccount,
                $amount,
                $request->description,
                false,
                $request->date,
                $request->customer_id
            );

            if ($customer->balance >= 0) {
                // Create payable transaction
                $payableAccount = Account::find(2);
                $this->createTransaction(
                    'Payable',
                    $payableAccount,
                    $amount,
                    $request->description,
                    false,
                    $request->date,
                    $request->customer_id
                );
            } else {
                $receivableAccount = Account::find(3);

                if ($remainingBalance >= 0) {
                    // Handle clearing of negative balance
                    $this->createTransaction(
                        'Receivable',
                        $receivableAccount,
                        abs($customer->balance),
                        'update customer balance',
                        true,
                        $request->date,
                        $request->customer_id
                    );

                    // Create payable transaction for remaining positive balance
                    if ($remainingBalance > 0) {
                        $payableAccount = Account::find(2);
                        $this->createTransaction(
                            'Payable',
                            $payableAccount,
                            $remainingBalance,
                            $request->description,
                            false,
                            $request->date,
                            $request->customer_id
                        );
                    }
                } else {
                    // Handle partial payment of negative balance
                    $this->createTransaction(
                        'Receivable',
                        $receivableAccount,
                        $amount,
                        'update customer balance',
                        true,
                        $request->date,
                        $request->customer_id
                    );
                }
            }

            $customer->balance += $amount;
            $customer->save();
        });

        Toastr::success(translate('Customer balance updated successfully'));
        return back();
    }
}
