<?php

namespace App\Http\Controllers;

use App\Models\BranchModel;
use App\Models\ClientModel;
use App\Models\CompanyModel;
use App\Models\InvoiceEmiDtlsModel;
use App\Models\InvoiceEmiModel;
use App\Models\InvoiceItemModel;
use App\Models\InvoiceItemTaxModel;
use App\Models\InvoiceModel;
use App\Models\PaymentQRModel;
use App\Models\PaymentsModel;
use App\Models\PaymentStatusModel;
use App\Models\ProductModel;
use App\Models\TaxesModel;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Barryvdh\DomPDF\Facade\Pdf;

class InvoiceEmiController extends Controller
{

    public function index()
    {
        $invoiceEmi = InvoiceEmiModel::orderBy('id', 'desc')->get();
        $invoices = InvoiceModel::with('client.user')
            ->where('branch_id', session('branch_id'))
            ->whereIn('invoice_id', $invoiceEmi->pluck('invoice_id'))
            ->get();

        $payment_status = PaymentStatusModel::all();

        return view('invoice-emi.index', compact('invoices', 'payment_status'));
    }

    public function add()
    {
        $clients = ClientModel::with('user')->get();

        $currencies = DB::table('currencies')->get();

        $qr_codes = PaymentQRModel::where('is_default', 1)->where('branch_id', session('branch_id'))->get();

        $all_taxes = TaxesModel::where('is_default', 1)->where('branch_id', session('branch_id'))->get();

        $payment_status = DB::table('payment_status')->get();

        $products = ProductModel::where('branch_id', session('branch_id'))->whereIn('product_type', [2, 3])->get();

        $discount_types = DB::table('discount_type')->get();

        $default_taxes = TaxesModel::where('show_flg', 'Y')->where('branch_id', session('branch_id'))->pluck('id')->toArray();


        return view('invoice-emi.add', compact('clients', 'currencies', 'default_taxes', 'qr_codes', 'all_taxes', 'payment_status', 'products', 'discount_types'));
    }

    public function store(Request $request)
    {
        $rules = [
            'invoice_date' => 'required|date',
            'due_date' => 'required|date',
            'sub_total' => 'required|numeric',
            'total_amt' => 'nullable|numeric',
            'discount_type' => 'nullable|numeric',
            'note' => 'nullable|string',
            'term' => 'nullable|string',
            'gst' => 'required|in:Y,N',
            'no_of_month' => 'required|integer',
            'interest_rate' => 'required|numeric|between:0,100',
            'dynamicFields.*.product' => 'required|exists:products,id',
            'dynamicFields.*.qty' => 'required|numeric|lte:dynamicFields.*.avl_qty',
            'dynamicFields.*.unit_price' => 'required|numeric',
            'dynamicFields.*.amount' => 'required|numeric',
            'status' => 'required',
            'client_name' => 'required_if:client_num,=,""',
            'client_num' => 'required',
        ];

        if ($request->gst == "Y") {
            $rules['dynamicFields.*.tax'] = 'required|array';
            $rules['dynamicFields.*.tax.*'] = 'required|numeric|gt:0';
        }

        if (!empty($request->discount_type)) {
            $rules['discount'] = 'required|numeric';
        }

        $request->validate($rules);

        if (($request->cash + $request->upi + $request->online) > $request->total_amt) {
            return back()->with('error', 'The total of cash, UPI, and online payments cannot exceed the total amount.');
        }


        DB::beginTransaction();

        try {          
            $client_id = $this->saveClient($request);

            $invoice_id = getPrefixes($request, $client_id);

            $invoice = InvoiceModel::create([
                'invoice_id' => $invoice_id,
                'client_id' => $client_id,
                'invoice_date' => $request->invoice_date,
                'due_date' => $request->due_date,
                'status' => $request->status,
                'payment_qr_code_id' => $request->qr_code,
                'currency_id' => 3,
                'recurring' => $request->recurring ?? false,
                'recurring_cycle' => $request->recurring_cycle,
                'amount' => $request->sub_total,
                'final_amount' => $request->total_amt,
                'discount_type' => $request->discount_type,
                'discount' => $request->discount,
                'note' => $request->note,
                'term' => $request->term,
                'gst' => $request->gst,
                'template_id' => 1,
                'branch_id' => session('branch_id'),
                'oprntl_flag' => 'E',
            ]);

            foreach ($request->dynamicFields as $field) {
                $item = InvoiceItemModel::create([
                    'invoice_id' => $invoice->id,
                    'product_id' => $field['product'],
                    'product_name' => ProductModel::find($field['product'])->name,
                    'quantity' => $field['qty'],
                    'price' => $field['unit_price'],
                    'margin_price' => ProductModel::find($field['product'])->margin_price,
                    'total' => $field['amount'],
                ]);

                $product = ProductModel::findOrFail($field['product']);
                $product->qty = $product->qty - (int) $field['qty'];
                $product->save();

                if ($request->gst == "Y") {
                    foreach ($field['tax'] as $taxId) {
                        InvoiceItemTaxModel::create([
                            'invoice_item_id' => $item->id,
                            'tax_id' => $taxId,
                            'tax' => TaxesModel::find($taxId)->value,
                        ]);
                    }
                }
            }

            if ($request->status == '2' || $request->status == '3') {
                if (!empty($request->upi)) {
                    PaymentsModel::create([
                        'invoice_id' => $invoice->id,
                        'amount' => $request->upi,
                        'total_amount' => $request->total_amt,
                        'payment_mode' => 1
                    ]);
                }
                if (!empty($request->cash)) {
                    PaymentsModel::create([
                        'invoice_id' => $invoice->id,
                        'amount' => $request->cash,
                        'total_amount' => $request->total_amt,
                        'payment_mode' => 3
                    ]);
                }
                if (!empty($request->online)) {
                    PaymentsModel::create([
                        'invoice_id' => $invoice->id,
                        'amount' => $request->online,
                        'total_amount' => $request->total_amt,
                        'payment_mode' => 2
                    ]);
                }
            }

            $downPayment = $request->cash + $request->upi + $request->online;

            $paid_amount = PaymentsModel::where('invoice_id', $invoice->id)->first();

            if (!empty($paid_amount)) {
                $amount = $paid_amount->total_amount - $downPayment;
            } else {
                $amount = $invoice->final_amount;
            }

            $totalAmount = $amount;

            $interest = ($totalAmount * $request->interest_rate) / 100;

            $totalAmountWithInterest = $totalAmount + $interest;

            $invoice_emi = InvoiceEmiModel::create([
                'invoice_id' => $invoice->invoice_id,
                'actual_amount' => max($totalAmountWithInterest, 2),
                'intersest_rate' => $request->interest_rate,
                'no_of_emi' => $request->no_of_month,
                'start_date' => $request->start_date,
                'penalty_amount' => $request->penalty_amount,
                'down_payment' => $downPayment,
                'emi_amount' => max($interest, 2),
            ]);

            $noOfMonths = $request->no_of_month;
            $monthlyEmi = $totalAmountWithInterest / $noOfMonths;
            $currentDate = Carbon::createFromFormat('Y-m-d', $request->start_date);

            for ($i = 0; $i < $request->no_of_month; $i++) {
                InvoiceEmiDtlsModel::create([
                    'invoice_emi_id' => $invoice_emi->id,
                    'emi_date' => $currentDate->format('Y-m-d'),
                    'emi_amount' => round($monthlyEmi, 2),
                ]);
                $currentDate->addMonth();
            }

            DB::commit();

            return redirect()->route('invoice-emi-index')->with('success', 'Invoice EMI created successfully!');

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', 'Oops! something went wrong');
        }
    }

    public function edit($id)
    {
        $invoice = InvoiceModel::with('client.user', 'invoiceItems.invoiceItemTaxes')
            ->where('id', $id)
            ->firstOrFail();

        $clients = ClientModel::with('user')->get();

        $currencies = DB::table('currencies')->get();

        $qr_codes = PaymentQRModel::where('is_default', 1)->where('branch_id', session('branch_id'))->get();

        $all_taxes = TaxesModel::where('is_default', 1)->where('branch_id', session('branch_id'))->get();

        $payment_status = DB::table('payment_status')->get();

        $products = ProductModel::where('branch_id', session('branch_id'))->whereIn('product_type', [2, 3])->get();

        $discount_types = DB::table('discount_type')->get();

        $default_taxes = TaxesModel::where('show_flg', 'Y')->where('branch_id', session('branch_id'))->pluck('id')->toArray();

        $dynamicFields = $invoice->invoiceItems->map(function ($item) {
            $qty = ProductModel::firstWhere('id', $item->product_id)->qty;
            return [
                'product' => $item->product_id,
                'avl_qty' => $qty >= 0 ? $qty : 0,
                'qty' => $item->quantity,
                'unit_price' => $item->price,
                'tax' => $item->invoiceItemTaxes->pluck('tax_id')->toArray() ?? [],
                'amount' => $item->total,
            ];
        })->toArray();

        return view('invoice-emi.edit', compact(
            'invoice',
            'clients',
            'currencies',
            'default_taxes',
            'qr_codes',
            'all_taxes',
            'payment_status',
            'products',
            'discount_types',
            'dynamicFields'
        ));
    }

    public function update(Request $request, $id)
    {
        $rules = [
            'invoice_date' => 'required|date',
            'due_date' => 'required|date',
            'sub_total' => 'required|numeric',
            'total_amt' => 'nullable|numeric',
            'discount_type' => 'nullable|numeric',
            'note' => 'nullable|string',
            'term' => 'nullable|string',
            'gst' => 'required|in:Y,N',
            'dynamicFields.*.product' => 'required|exists:products,id',
            'dynamicFields.*.qty' => 'required|numeric|lte:dynamicFields.*.avl_qty',
            'dynamicFields.*.unit_price' => 'required|numeric',
            'dynamicFields.*.amount' => 'required|numeric',
        ];

        if (!empty($request->discount_type)) {
            $rules['discount'] = 'required|numeric';
        }

        if ($request->gst == "Y") {
            $rules['dynamicFields.*.tax'] = 'required|array';
            $rules['dynamicFields.*.tax.*'] = 'required|numeric|gt:0';
        }

        $request->validate($rules);

        DB::beginTransaction();

        try {
            $invoice = InvoiceModel::findOrFail($id);

            $invoice->update([
                'invoice_id' => $request->invoice_id,
                'client_id' => $request->client,
                'invoice_date' => $request->invoice_date,
                'due_date' => $request->due_date,
                'amount' => $request->sub_total,
                'final_amount' => $request->total_amt,
                'discount_type' => $request->discount_type,
                'discount' => $request->discount,
                'note' => $request->note,
                'term' => $request->term,
                'currency_id' => 3,
                'template_id' => 1,
                'payment_qr_code_id' => $request->qr_code,
                'recurring' => $request->recurring ?? false,
                'recurring_cycle' => $request->recurring_cycle,
                'status' => $request->status,
                'gst' => $request->gst,
                'oprntl_flag' => 'E'
            ]);

            $invoice->invoiceItems->each(function ($item) {
                $product = ProductModel::findOrFail($item->product_id);
                $product->qty = $product->qty + $item->quantity;
                $product->save();
                $item->invoiceItemTaxes()->delete();
            });

            $invoice->invoiceItems()->delete();

            foreach ($request->dynamicFields as $field) {
                $item = InvoiceItemModel::create([
                    'invoice_id' => $invoice->id,
                    'product_id' => $field['product'],
                    'product_name' => ProductModel::find($field['product'])->name,
                    'quantity' => $field['qty'],
                    'price' => $field['unit_price'],
                    'margin_price' => ProductModel::find($field['product'])->margin_price,
                    'total' => $field['amount'],
                ]);

                $product = ProductModel::findOrFail($field['product']);
                $product->qty = $product->qty - (int) $field['qty'];
                $product->save();

                if ($request->gst == "Y") {
                    foreach ($field['tax'] as $taxId) {
                        InvoiceItemTaxModel::create([
                            'invoice_item_id' => $item->id,
                            'tax_id' => $taxId,
                            'tax' => TaxesModel::find($taxId)->value,
                        ]);
                    }
                }
            }

            DB::commit();
            return redirect()->route('invoice-emi.index')->with('success', 'Invoice updated successfully!');

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', 'Oops! something went wrong');
        }
    }

    public function delete($id)
    {
        DB::beginTransaction();

        try {
            $invoice = InvoiceModel::findOrFail($id);

            $invoice->invoiceItems->each(function ($item) {
                $product = ProductModel::findOrFail($item->product_id);
                $product->qty = $product->qty + $item->quantity;
                $product->save();
                $item->invoiceItemTaxes()->delete();
            });

            $invoice_emi = InvoiceEmiModel::with('invoice_emi_dtls')->where('invoice_id', $invoice->invoice_id)->first();
            if ($invoice_emi) {
                $invoice_emi->invoice_emi_dtls->each(function ($item) {
                    $dtls = InvoiceEmiDtlsModel::where('id', $item->id)->get();
                    if ($dtls) {
                        foreach ($dtls as $data) {
                            $data->delete();
                        }
                    }
                });
                $invoice_emi->delete();
            }

            $invoice->payments()->delete();
            $invoice->invoiceItems()->delete();
            $invoice->delete();

            DB::commit();
            return redirect()->route('invoice-emi-index')->with('success', 'Invoice EMI deleted successfully!');

        } catch (\Exception $e) {

            DB::rollBack();
            dd($e);
            return back()->with('error', 'An error occurred while deleting the invoice!');
        }
    }

    public function payment($id)
    {
        $invoice = InvoiceModel::findOrFail($id);
        $invoice_emi = InvoiceEmiModel::with('invoice.client.user')->where('invoice_id', $invoice->invoice_id)->first();

        if (!$invoice_emi) {
            return back()->with('error', 'No EMI details found for this invoice');
        }

        $invoice_dtls = InvoiceEmiDtlsModel::with('invoice_emi')->where('invoice_emi_id', $invoice_emi->id)->get();

        $pre_closure_amount = 0;
        $remaining_emis = 0;
        $total_penalty_amount = 0;
        $today = now();
        $daysPast = 0;

        foreach ($invoice_dtls as $data) {
            if ($data->oprntl_flag !== 'P' && $data->oprntl_flag !== 'C') {
                $pre_closure_amount += $data->emi_amount;
                $remaining_emis++;

                $emiDate = \Carbon\Carbon::parse($data->emi_date);

                if (is_null($data->paid_date)) {
                    $daysPast = $emiDate->isPast() ? $emiDate->diffInDays($today) : 0;
                } else {
                    $paidDate = \Carbon\Carbon::parse($data->paid_date);
                    $daysPast = $emiDate->diffInDays($paidDate, false);
                }

                $penalty_amount = max(0, (int) $daysPast) * $invoice_emi->penalty_amount;
                $total_penalty_amount += $penalty_amount;

                $data->calculated_due_days = max(0, $daysPast);
                $data->calculated_penalty = $penalty_amount;
            }
        }
        return view('invoice-emi.payment', [
            'invoice' => $invoice,
            'invoice_dtls' => $invoice_dtls,
            'invoice_emi' => $invoice_emi,
            'pre_closure_amount' => $pre_closure_amount,
            'total_penalty_amount' => $total_penalty_amount
        ]);
    }
    public function savePayment(Request $request)
    {
        $request->validate([
            'emi_ids' => 'required|array',
            'emi_ids.*' => 'exists:invoice_emi_dtls,id',
            'paid_dates.*' => 'required|date',
            'penalties.*' => 'numeric|min:0',
            'discounts.*' => 'numeric|min:0',
            'totals.*' => 'numeric|min:0',
        ]);

        DB::beginTransaction();
        try {
            $currentPaymentTotal = 0;
            $invoiceEmi = null;

            foreach ($request->emi_ids as $emiId) {
                $emiDetail = InvoiceEmiDtlsModel::findOrFail($emiId);
                $invoiceEmi = InvoiceEmiModel::findOrFail($emiDetail->invoice_emi_id);

                $paidDate = $request->paid_dates[$emiId];
                $penalty = $request->penalties[$emiId] ?? 0;
                $discount = $request->discounts[$emiId] ?? 0;
                $totalAmount = $request->totals[$emiId];
                $dueDays = $request->due_days[$emiId] ?? 0;

                if (Carbon::parse($paidDate)->isFuture()) {
                    throw new \Exception('Paid date cannot be in the future');
                }

                $emiDetail->update([
                    'paid_date' => $paidDate,
                    'paid_amount' => $totalAmount,
                    'penalty' => $penalty,
                    'discount_amount' => $discount,
                    'total_amount' => $totalAmount,
                    'oprntl_flag' => 'P',
                ]);

                $currentPaymentTotal += $totalAmount;

                PaymentsModel::create([
                    'invoice_id' => $request->invoice_id,
                    'payment_mode' => 3,
                    'amount' => $totalAmount,
                    'payment_date' => $paidDate,
                    'oprntl_flag' => 'E',
                    'total_amount' => $invoiceEmi->actual_amount,
                    'invoioce_emi_dtls_id' => $emiDetail->id,
                ]);
            }

            $previousPaymentsTotal = PaymentsModel::where('invoice_id', $request->invoice_id)
                ->where('invoioce_emi_dtls_id', '!=', $emiDetail->id)
                ->sum('amount');

            $totalAllPayments = $previousPaymentsTotal + $currentPaymentTotal;

            if ($invoiceEmi && $totalAllPayments >= $invoiceEmi->actual_amount) {
                InvoiceModel::where('invoice_id', $invoiceEmi->invoice_id)
                    ->update(['status' => 2]);
            } else {
                InvoiceModel::where('invoice_id', $invoiceEmi->invoice_id)
                    ->update(['status' => 3]);
            }

            DB::commit();
            return redirect()->route('invoice-emi-payment', $request->invoice_id)
                ->with('success', 'Payment processed successfully');

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', $e->getMessage());
        }
    }
    public function preClosure(Request $request)
    {
        $request->validate([
            'pay' => 'required|numeric|lte:total',
            'paid_date' => 'required|date',
        ]);

        DB::beginTransaction();
        try {

            $invoice = InvoiceModel::with('invoice_emi.invoice_emi_dtls')->findOrFail($request->invoice_id);
            $emi = $invoice->invoice_emi->invoice_emi_dtls->where('oprntl_flag', '!=', 'P');

            $previousPaymentsTotal = $invoice->payments->sum('amount');
            $currentPayment = $request->pay;
            $totalPaid = $previousPaymentsTotal + $currentPayment;

            foreach ($emi as $detail) {
                if ($detail->oprntl_flag !== 'P') {
                    $detail->paid_date = $request->paid_date;
                    $detail->paid_amount = $request->pay;
                    $detail->discount_amount = $request->discount;
                    $detail->penalty = $request->penalty;
                    $detail->total_amount = $request->pay;
                    $detail->remarks = $request->remarks;
                    $detail->oprntl_flag = 'C';
                    $detail->save();
                    break;
                }
            }

            InvoiceEmiDtlsModel::where('invoice_emi_id', $invoice->invoice_emi->id)
                ->where(function ($query) {
                    $query->where('oprntl_flag', '!=', 'P')
                        ->orWhereNull('oprntl_flag');
                })
                ->update(['oprntl_flag' => 'C']);

            $status = ($totalPaid >= $invoice->invoice_emi->actual_amount) ? 2 : 3;
            $invoice->update([
                'status' => $status,
            ]);

            DB::commit();
            return redirect()->route('invoice-emi-payment', $request->invoice_id)->with('success', 'Pre-Closed Added Successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            \Log::info('While Executing the preclosure:' . $e);
            return back()->with('error', 'Something Went Wrong.');
        }
    }

    protected function saveClient($request)
    {
        $user = User::where('phone', $request->client_num)->first();

        try {
            if (!empty($user)) {
                $client = ClientModel::where('user_id', $user->id)->first();
                return $client->id;
            } else {
                $randomEmail = Str::random(10) . '@billing.com';
                $user = User::create([
                    'name' => $request->client_name,
                    'email' => $randomEmail,
                    'phone' => $request->client_num,
                    'password' => Hash::make('client@123'),
                    'user_flg' => 'C',
                    'active_status' => 'A',
                    'branch_id' => session('branch_id')
                ]);

                $client = ClientModel::create([
                    'user_id' => $user->id,
                    'branch_id' => session('branch_id'),
                    'active_status' => 'A',
                ]);

                return $client->id;
            }
        } catch (\Exception $e) {
            throw $e;
        }
    }
}