<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\CustomerTransaction;
use App\Models\UserAccount;
use App\Services\LedgerService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

class CustomerLedgerController extends Controller
{
    private function getCustomer($customer)
    {
        return Customer::where('user_id', auth()->id())
            ->findOrFail($customer->id ?? $customer);
    }

    private function getTransaction($customerId, $trx)
    {
        return CustomerTransaction::where('user_id', auth()->id())
            ->where('customer_id', $customerId)
            ->findOrFail($trx->id ?? $trx);
    }

    public function index(Customer $customer, Request $request)
    {
        $customer = $this->getCustomer($customer);

        $base = CustomerTransaction::query()
            ->where('user_id', auth()->id())
            ->where('customer_id', $customer->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('type')) {
            $base->where('type', $request->type);
        }

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

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

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

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

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

    public function edit($customerId, $trxId)
    {
        $customer = $this->getCustomer($customerId);
        $trx = $this->getTransaction($customer->id, $trxId);

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

        return match ($trx->type) {
            'bill' => view('user.customers.ledger.edit_bill', compact('customer', 'trx')),
            'payment' => view('user.customers.ledger.edit_payment', compact('customer', 'trx', 'accounts')),
            default => view('user.customers.ledger.edit_adjust', compact('customer', 'trx')),
        };
    }

    public function update(Request $request, $customerId, $trxId, LedgerService $ledger)
    {
        $customer = $this->getCustomer($customerId);
        $trx = $this->getTransaction($customer->id, $trxId);

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

            // ðŸ”¹ BILL (unchanged)
            if ($trx->type === 'bill') {

                $data = $request->validate([
                    'debit' => ['required', 'numeric', 'min:0.01'],
                    'note' => ['nullable', 'string', 'max:2000'],
                    'bill_no' => ['nullable', 'string', 'max:100'],
                    'bill_photo' => ['nullable', 'file', 'mimes:jpg,jpeg,png,webp,pdf', 'max:4096'],
                    'posted_at' => ['nullable', 'date'],
                ]);

                $updateData = [
                    'debit' => (float) $data['debit'],
                    'credit' => 0,
                    'note' => $data['note'] ?? null,
                    'bill_no' => $data['bill_no'] ?? null,
                    'posted_at' => $data['posted_at'] ?? $trx->posted_at,
                ];

                if ($request->hasFile('bill_photo')) {
                    $this->deletePublicFile($trx->bill_photo);
                    $updateData['bill_photo'] = $this->uploadPublicFile($request->file('bill_photo'), 'uploads/customer_bills');
                }

                $trx->update($updateData);
                return;
            }

            // ðŸ”¹ PAYMENT (unchanged)
            if ($trx->type === 'payment') {

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

                $accountId = (int) $data['user_account_id'];

                UserAccount::where('id', $accountId)
                    ->where('user_id', auth()->id())
                    ->firstOrFail();

                $trxNo = $trx->trx_no ?: $ledger->trxNo('CPAY');

                $updateData = [
                    'user_account_id' => $accountId,
                    'debit' => 0,
                    'credit' => (float) $data['credit'],
                    'note' => $data['note'] ?? null,
                    'posted_at' => $data['posted_at'] ?? $trx->posted_at,
                    'trx_no' => $trxNo,
                ];

                if ($request->hasFile('payment_proof_photo')) {
                    $this->deletePublicFile($trx->payment_proof_photo);
                    $updateData['payment_proof_photo'] = $this->uploadPublicFile($request->file('payment_proof_photo'), 'uploads/customer_payments');
                }

                $trx->update($updateData);

                $ledger->upsertAccountLedgerForReference(
                    auth()->id(),
                    $accountId,
                    'customer_payment',
                    $trxNo,
                    CustomerTransaction::class,
                    $trx->id,
                    (float) $data['credit'],
                    0,
                    $data['note'] ?? __('Customer_Ledger_Controller.defaults.customer_payment_received'),
                    $updateData['posted_at']
                );

                return;
            }

            // ðŸ”¹ ADJUST (unchanged)
            $data = $request->validate([
                'debit' => ['nullable', 'numeric', 'min:0'],
                'credit' => ['nullable', 'numeric', 'min:0'],
                'note' => ['nullable', 'string', 'max:2000'],
                'posted_at' => ['nullable', 'date'],
            ]);

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

            if ($debit <= 0 && $credit <= 0) {
                abort(422, __('Customer_Ledger_Controller.messages.debit_or_credit_must_be_greater_than_zero'));
            }

            $trx->update([
                'debit' => $debit,
                'credit' => $credit,
                'note' => $data['note'] ?? null,
                'posted_at' => $data['posted_at'] ?? $trx->posted_at,
            ]);
        });

        return redirect()
            ->route('user.customers.ledger.index', $customer)
            ->with('ok', __('Customer_Ledger_Controller.messages.transaction_updated_auto_adjusted'));
    }

    public function destroy($customerId, $trxId, LedgerService $ledger)
    {
        $customer = $this->getCustomer($customerId);
        $trx = $this->getTransaction($customer->id, $trxId);

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

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

            $this->deletePublicFile($trx->bill_photo);
            $this->deletePublicFile($trx->payment_proof_photo);

            $trx->delete();
        });

        return redirect()
            ->route('user.customers.ledger.index', $customer)
            ->with('ok', __('Customer_Ledger_Controller.messages.transaction_deleted_auto_adjusted'));
    }

    public function createAdjust($customerId)
    {
        $customer = $this->getCustomer($customerId);

        return view('user.customers.ledger.create_adjust', compact('customer'));
    }

    public function storeAdjust(Request $request, $customerId)
    {
        $customer = $this->getCustomer($customerId);

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

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

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

        CustomerTransaction::create([
            'user_id' => auth()->id(),
            'customer_id' => $customer->id,
            'type' => 'adjust',
            'trx_no' => null,
            'debit' => $debit,
            'credit' => $credit,
            'note' => $data['note'] ?? null,
            'user_account_id' => null,
            'bill_no' => null,
            'bill_photo' => null,
            'payment_proof_photo' => null,
            'posted_at' => $data['posted_at'] ?? now(),
        ]);

        return redirect()
            ->route('user.customers.ledger.index', $customer)
            ->with('ok', __('Customer_Ledger_Controller.messages.adjust_entry_added'));
    }

    // ðŸ”» FILE FUNCTIONS UNCHANGED
    private function uploadPublicFile($file, string $folder): string
    {
        $folder = trim($folder, '/');
        $destination = public_path($folder);

        if (!File::exists($destination)) {
            File::makeDirectory($destination, 0755, true, true);
        }

        $extension = strtolower($file->getClientOriginalExtension());
        $fileName = Str::uuid() . '.' . $extension;

        $file->move($destination, $fileName);

        return $folder . '/' . $fileName;
    }

    private function deletePublicFile(?string $path): void
    {
        if (!$path) return;

        $fullPath = public_path($path);

        if (File::exists($fullPath) && File::isFile($fullPath)) {
            File::delete($fullPath);
        }
    }
}