<?php

namespace App\Http\Controllers\User;

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

class SupplierLedgerController extends Controller
{
    private function getSupplier($supplier)
    {
        return Supplier::where('user_id', auth()->id())
            ->findOrFail($supplier->id ?? $supplier);
    }

    private function getTransaction($supplierId, $trx)
    {
        return SupplierTransaction::where('user_id', auth()->id())
            ->where('supplier_id', $supplierId)
            ->findOrFail($trx->id ?? $trx);
    }

    public function index(Supplier $supplier, Request $request)
    {
        $supplier = $this->getSupplier($supplier);

        $q = SupplierTransaction::where('user_id', auth()->id())
            ->where('supplier_id', $supplier->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);
        }

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

        if ($request->filled('search')) {
            $s = trim($request->search);
            $q->where(function ($qq) use ($s) {
                $qq->where('note', 'like', "%{$s}%")
                   ->orWhere('memo_no', 'like', "%{$s}%");
            });
        }

        $transactions = (clone $q)->orderByDesc('posted_at')->orderByDesc('id')
            ->paginate(20)->withQueryString();

        $sum_debit = (float) (clone $q)->sum('debit');
        $sum_credit = (float) (clone $q)->sum('credit');
        $current_due = $sum_debit - $sum_credit;

        return view('user.suppliers.ledger.index', compact(
            'supplier',
            'transactions',
            'sum_debit',
            'sum_credit',
            'current_due'
        ));
    }

    public function createPurchase($supplierId)
    {
        $supplier = $this->getSupplier($supplierId);

        return view('user.suppliers.ledger.create_purchase', compact('supplier'));
    }

    public function storePurchase($supplierId, Request $request)
    {
        $supplier = $this->getSupplier($supplierId);

        try {
            $data = $request->validate([
                'debit' => ['required','numeric','min:01.0'],
                'note' => ['required','string','max:100'],
                'memo_no' => ['nullable','string','max:10'],
                'memo_photo' => ['nullable','file','mimes:jpg,jpeg,png,webp,pdf','max:4096'],
                'posted_at' => ['nullable','date'],
            ]);

            DB::transaction(function () use ($supplier, $data, $request) {

                $photo = null;

                if ($request->hasFile('memo_photo')) {
                    $file = $request->file('memo_photo');
                    $dir = public_path('uploads/supplier_memos');

                    if (!file_exists($dir)) mkdir($dir,0755,true);

                    $filename = time().'_'.uniqid().'.'.$file->getClientOriginalExtension();
                    $file->move($dir,$filename);

                    $photo = 'uploads/supplier_memos/'.$filename;
                }

                SupplierTransaction::create([
                    'user_id'=>auth()->id(),
                    'supplier_id'=>$supplier->id,
                    'type'=>'purchase',
                    'trx_no'=>null,
                    'debit'=>(float)$data['debit'],
                    'credit'=>0,
                    'note'=>$data['note'],
                    'memo_no'=>$data['memo_no']??null,
                    'memo_photo'=>$photo,
                    'payment_proof_photo'=>null,
                    'user_account_id'=>null,
                    'posted_at'=>$data['posted_at']??now(),
                ]);
            });

            return redirect()
                ->route('user.suppliers.ledger.index',$supplier)
                ->with('ok', __('Supplier_Ledger_Controller.messages.purchase_added'));

        } catch (\Throwable $e) {
            report($e);
            return back()->withInput()->with('err', __('Supplier_Ledger_Controller.messages.failed'));
        }
    }

    public function createPayment($supplierId)
    {
        $supplier = $this->getSupplier($supplierId);

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

        return view('user.suppliers.ledger.create_payment', compact('supplier','accounts'));
    }

    public function storePayment($supplierId, Request $request, LedgerService $ledger)
    {
        $supplier = $this->getSupplier($supplierId);

        try {
            $data = $request->validate([
                'user_account_id'=>['required','integer'],
                'credit'=>['required','numeric','min:01.0'],
                'note'=>['nullable','string','max:100'],
                'payment_proof_photo'=>['nullable','file','mimes:jpg,jpeg,png,webp,pdf','max:4096'],
                'posted_at'=>['nullable','date'],
            ]);

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

            DB::transaction(function () use ($supplier,$data,$request,$ledger,$account) {

                $proof = null;

                if ($request->hasFile('payment_proof_photo')) {
                    $file=$request->file('payment_proof_photo');
                    $dir=public_path('uploads/supplier_payments');

                    if (!file_exists($dir)) mkdir($dir,0755,true);

                    $filename=time().'_'.uniqid().'.'.$file->getClientOriginalExtension();
                    $file->move($dir,$filename);

                    $proof='uploads/supplier_payments/'.$filename;
                }

                $trxNo=$ledger->trxNo('SPAY');

                $trx = SupplierTransaction::create([
                    'user_id'=>auth()->id(),
                    'supplier_id'=>$supplier->id,
                    'type'=>'payment',
                    'trx_no'=>$trxNo,
                    'debit'=>0,
                    'credit'=>(float)$data['credit'],
                    'note'=>$data['note']??null,
                    'payment_proof_photo'=>$proof,
                    'user_account_id'=>$account->id,
                    'posted_at'=>$data['posted_at']??now(),
                ]);

                $ledger->upsertAccountLedgerForReference(
                    auth()->id(),
                    $account->id,
                    'supplier_payment',
                    $trxNo,
                    SupplierTransaction::class,
                    $trx->id,
                    0,
                    (float)$data['credit'],
                    __('Supplier_Ledger_Controller.defaults.supplier_payment'),
                    $trx->posted_at
                );
            });

            return redirect()
                ->route('user.suppliers.ledger.index',$supplier)
                ->with('ok', __('Supplier_Ledger_Controller.messages.payment_added_account_ledger_posted'));

        } catch (\Throwable $e) {
            report($e);
            return back()->withInput()->with('err', __('Supplier_Ledger_Controller.messages.failed'));
        }
    }

    public function createAdjust($supplierId)
    {
        $supplier = $this->getSupplier($supplierId);

        return view('user.suppliers.ledger.create_adjust', compact('supplier'));
    }

    public function storeAdjust($supplierId, Request $request)
    {
        $supplier = $this->getSupplier($supplierId);

        try {
            $data = $request->validate([
                'debit'=>['nullable','numeric','min:0'],
                'credit'=>['nullable','numeric','min:0'],
                'note'=>['required','string','max:100'],
                'posted_at'=>['nullable','date'],
            ]);

            $debit=(float)($data['debit']??0);
            $credit=(float)($data['credit']??0);

            if ($debit<=0 && $credit<=0) {
                return back()->with('err', __('Supplier_Ledger_Controller.messages.debit_or_credit_must_be_greater_than_zero'))->withInput();
            }

            SupplierTransaction::create([
                'user_id'=>auth()->id(),
                'supplier_id'=>$supplier->id,
                'type'=>'adjust',
                'trx_no'=>null,
                'debit'=>$debit,
                'credit'=>$credit,
                'note'=>$data['note'],
                'posted_at'=>$data['posted_at']??now(),
            ]);

            return redirect()
                ->route('user.suppliers.ledger.index',$supplier)
                ->with('ok', __('Supplier_Ledger_Controller.messages.adjust_added'));

        } catch (\Throwable $e) {
            report($e);
            return back()->withInput()->with('err', __('Supplier_Ledger_Controller.messages.failed'));
        }
    }

    public function edit($supplierId, $trxId)
    {
        $supplier = $this->getSupplier($supplierId);
        $trx = $this->getTransaction($supplier->id,$trxId);

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

        return match ($trx->type) {
            'purchase'=>view('user.suppliers.ledger.edit_purchase',compact('supplier','trx')),
            'payment'=>view('user.suppliers.ledger.edit_payment',compact('supplier','trx','accounts')),
            default=>view('user.suppliers.ledger.edit_adjust',compact('supplier','trx')),
        };
    }

    public function destroy($supplierId, $trxId, LedgerService $ledger)
    {
        $supplier = $this->getSupplier($supplierId);
        $trx = $this->getTransaction($supplier->id,$trxId);

        try {
            DB::transaction(function () use ($trx,$ledger) {

                if ($trx->type === 'payment') {
                    $ledger->deleteAccountLedgerByReference(
                        SupplierTransaction::class,
                        $trx->id
                    );
                }

                $trx->delete();
            });

            return redirect()
                ->route('user.suppliers.ledger.index',$supplier)
                ->with('ok', __('Supplier_Ledger_Controller.messages.deleted_synced'));

        } catch (\Throwable $e) {
            report($e);

            return redirect()
                ->route('user.suppliers.ledger.index',$supplier)
                ->with('err', __('Supplier_Ledger_Controller.messages.failed'));
        }
    }
}