<?php

namespace App\Http\Controllers;

use App\Models\BranchModel;
use App\Models\ClientModel;
use App\Models\InvoiceItemModel;
use App\Models\InvoiceItemTaxModel;
use App\Models\InvoiceModel;
use App\Models\LoyaltyTransactionModel;
use App\Models\PaymentQRModel;
use App\Models\PaymentsModel;
use App\Models\PaymentStatusModel;
use App\Models\ProductModel;
use App\Models\RightsModel;
use App\Models\StandardPaperSizeModel;
use App\Models\TaxesModel;
use App\Models\User;
use App\Providers\WhatsAppService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;

class InvoiceController extends Controller
{
    public $whatsappService;

    public function __construct()
    {
        $this->whatsappService = new WhatsAppService();
    }

    public function index()
    {
        if (Auth::user()->user_flg == 'C') {
            $client_id = ClientModel::where('user_id', Auth::user()->id)->pluck('id')->first();
            $invoices = InvoiceModel::with('client.user', 'createdBy')->where('branch_id', session('branch_id'))
                ->where('oprntl_flag', 'A')->where('client_id', $client_id)->get();
        } else {
            $invoices = InvoiceModel::with('client.user', 'createdBy')->where('branch_id', session('branch_id'))
                ->where('oprntl_flag', 'A')->orderBy('id', 'desc')->get();
        }
        $payment_status = PaymentStatusModel::all();

        $paper = BranchModel::with('paper')->where('id', session('branch_id'))->first();
        $paper_id = $paper->paper_size;

        return view('invoices.index', compact('invoices', 'payment_status', 'paper_id'));
    }

    public function add()
    {
        $data = [
            'invoice_date' => Carbon::now()->toDateString(),
            'due_date' => Carbon::now()->toDateString(),
            'clients' => ClientModel::with('user')->get(),
            'currencies' => DB::table('currencies')->get(),
            'qr_codes' => PaymentQRModel::where('is_default', 1)->where('branch_id', session('branch_id'))->get(),
            'default_taxes' => TaxesModel::where('is_default', 1)->where('branch_id', session('branch_id'))->pluck('id')->toArray(),
            'all_taxes' => TaxesModel::where('show_flg', 'Y')->where('branch_id', session('branch_id'))->get() ?? [],
            'payment_status' => DB::table('payment_status')->get(),
            'products' => ProductModel::with('branch')->where('branch_id', session('branch_id'))->whereIn('product_type', [2, 3])->get(),
            'discount_types' => DB::table('discount_type')->get(),
            'gst' => 'Y',
            'point_value' => BranchModel::where('id', session('branch_id'))->first()->value('point_redemption'),
            'branch' => BranchModel::where('id', session('branch_id'))->first(),
        ];

        return view('invoices.add', $data);
    }

    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',
            // 'status' => 'required',
            '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 (empty($request->client_num)) {
            $rules['client_num'] = 'required';
        }

        $user = User::where('phone', $request->client_num)->first();
        if (empty($user)) {
            $rules['client_name'] = 'required|string';
        }

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

        $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 = saveClient($request);         

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

            $loyalty = BranchModel::where('id', session('branch_id'))->first();

            $clientPoints = ClientModel::where('id', $client_id)->first();

            $loyalty_amount = $loyalty->loyalty_amount;
            $loyalty_config = $loyalty->loyalty_config;

            if (!empty($request->redeem_points)) {
                $current_point = $request->available_point - $request->redeem_points;

                LoyaltyTransactionModel::create([
                    'client_id' => $client_id,
                    'points' => $request->redeem_points,
                    'type' => 'redeem',
                    'reference_invoice' => $invoice_id,
                    'created_by' => Auth::user()->id,
                ]);
                $clientPoints->update([
                    'loyalty_points' => $current_point,
                ]);

            }

            if ($loyalty_config == 'A') {
                $earned_points = floor($request->total_amt / $loyalty_amount);
                $points = $clientPoints->loyalty_points + $earned_points;
                $clientPoints->update([
                    'loyalty_points' => $points,
                ]);

                LoyaltyTransactionModel::create([
                    'client_id' => $client_id,
                    'points' => $earned_points,
                    'type' => 'earn',
                    'reference_invoice' => $invoice_id,
                    'created_by' => Auth::user()->id,
                ]);

            }
            $paid_amount = $request->upi + $request->cash + $request->online;
            if ($paid_amount == 0) {
                $status = 'Unpaid';
            } elseif ($paid_amount == $request->total_amt) {
                $status = 'Paid';
            } else {
                $status = 'Partially Paid';
            }
            $status_id = PaymentStatusModel::where('name', $status)->value('id');

            $invoice = InvoiceModel::create([
                'invoice_id' => $invoice_id,
                'client_id' => $client_id,
                'invoice_date' => $request->invoice_date,
                'due_date' => $request->due_date,
                'status' => $status_id,
                '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'),
                'created_by' => Auth::user()->id,
            ]);

            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'],
                    'description' => $field['description'] ?? '',
                ]);

                $product = ProductModel::findOrFail($field['product']);
                $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 ($status_id == '2' || $status_id == '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
                    ]);
                }
            }

            DB::commit();
            return redirect()->route('pdf', $invoice->id)
                ->with('success', 'Invoice created successfully!');

        } catch (\Exception $e) {
            DB::rollBack();
            \Log::info('While Creating a Invoice' . $e->getMessage());
            return back()->with('error', 'Oops! something went wrong');
        }
    }

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

        $data = [
            'invoice' => $invoice,
            'invoice_id' => $invoice->invoice_id,
            'client' => $invoice->client_id,
            'invoice_date' => $invoice->invoice_date,
            'due_date' => $invoice->due_date,
            'total_amt' => $invoice->final_amount,
            'discount_type' => $invoice->discount_type,
            'discount' => $invoice->discount,
            'note' => $invoice->note,
            'term' => $invoice->term,
            'qr_code' => $invoice->payment_qr_code_id,
            'recurring' => $invoice->recurring,
            'recurring_cycle' => $invoice->recurring_cycle,
            'status' => $invoice->status,
            'discount_amt' => $invoice->discount,
            'client_name' => $invoice->client->user->name,
            'client_num' => $invoice->client->user->phone,
            'gst' => $invoice->gst,
            'dynamicFields' => $invoice->invoiceItems->map(function ($item) {
                $qty = ProductModel::where('id', $item->product_id)->value('qty') ?? 0;
                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(),
            'clients' => ClientModel::with('user')->get(),
            'currencies' => DB::table('currencies')->get(),
            'qr_codes' => PaymentQRModel::where('is_default', 1)->where('branch_id', session('branch_id'))->get(),
            'default_taxes' => TaxesModel::where('is_default', 1)->where('branch_id', session('branch_id'))->pluck('id')->toArray(),
            'all_taxes' => TaxesModel::where('show_flg', 'Y')->where('branch_id', session('branch_id'))->get() ?? [],
            'payment_status' => DB::table('payment_status')->get(),
            'products' => ProductModel::with('branch')->where('branch_id', session('branch_id'))->whereIn('product_type', [2, 3])->get(),
            'discount_types' => DB::table('discount_type')->get(),
            'point_value' => BranchModel::where('id', session('branch_id'))->first()->value('point_redemption'),
            'branch' => BranchModel::where('id', session('branch_id'))->first(),
            'redeem' => LoyaltyTransactionModel::where('type', 'redeem')->where('reference_invoice', $invoice->invoice_id)->where('client_id', $invoice->client_id)->first(),
            'dueAmount' => $this->dueAmount($invoice->client),
        ];

        return view('invoices.edit', $data);
    }

    // Update existing invoice
    public function update(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',
            '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::where('id', $request->id)->firstOrFail();
            $payment = PaymentsModel::where('invoice_id', $invoice->id)->sum('amount');

            $loyalty = BranchModel::where('id', session('branch_id'))->first();

            $clientPoints = ClientModel::where('id', $invoice->client_id)->first();

            $loyalty_amount = $loyalty->loyalty_amount;
            $loyalty_config = $loyalty->loyalty_config;

            if ($loyalty_config == 'A') {

                if (!empty($request->redeem_points)) {
                    $redeem = LoyaltyTransactionModel::where('type', 'redeem')
                        ->where('client_id', $invoice->client_id)
                        ->where('reference_invoice', $invoice->invoice_id)
                        ->first();

                    $old_redeem_points = $redeem ? $redeem->points : 0;
                    $new_redeem_points = $request->redeem_points;
                    $current_point = $clientPoints->loyalty_points;

                    if ($new_redeem_points > $old_redeem_points) {
                        $extra = $new_redeem_points - $old_redeem_points;
                        $current_point = $current_point - $extra;
                    } elseif ($new_redeem_points < $old_redeem_points) {
                        $less = $old_redeem_points - $new_redeem_points;
                        $current_point = $current_point + $less;
                    }

                    if ($redeem) {
                        $redeem->update([
                            'points' => $new_redeem_points,
                        ]);
                    } else {
                        LoyaltyTransactionModel::create([
                            'client_id' => $invoice->client_id,
                            'points' => $new_redeem_points,
                            'type' => 'redeem',
                            'reference_invoice' => $invoice->invoice_id,
                            'branch_id' => session('branch_id'),
                            'created_by' => Auth::user()->id,
                        ]);
                    }

                    $clientPoints->update([
                        'loyalty_points' => $current_point,
                    ]);
                }

                $oldEarnedTransaction = LoyaltyTransactionModel::where('type', 'earn')
                    ->where('client_id', $invoice->client_id)
                    ->where('reference_invoice', $invoice->invoice_id)
                    ->first();

                $old_earned_points = $oldEarnedTransaction ? $oldEarnedTransaction->points : 0;
                $new_earned_points = floor($request->total_amt / $loyalty_amount);
                $current_points = $clientPoints->loyalty_points - $old_earned_points + $new_earned_points;

                $clientPoints->update([
                    'loyalty_points' => $current_points,
                ]);

                if ($oldEarnedTransaction) {
                    $oldEarnedTransaction->update([
                        'points' => $new_earned_points,
                    ]);
                } else {

                    LoyaltyTransactionModel::create([
                        'client_id' => $invoice->client_id,
                        'points' => $new_earned_points,
                        'type' => 'earn',
                        'reference_invoice' => $invoice->invoice_id,
                        'branch_id' => session('branch_id'),
                        'created_by' => Auth::user()->id,
                    ]);
                }
            }

            $status = 'Unpaid';
            if ($payment) {
                if ($payment == $request->total_amt) {
                    $status = 'Paid';
                } else {
                    $status = 'Partially Paid';
                }
            }
            $status_id = PaymentStatusModel::where('name', $status)->pluck('id')->first();

            $invoice->update([
                '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' => $status_id,
                'gst' => $request->gst,
                'updated_by' => Auth::user()->id,
                'delivery_status' => $request->delivery_status,
            ]);

            $productIds = [];

            foreach ($request->dynamicFields as $field) {
                $product = ProductModel::find($field['product']);
                if (!$product)
                    continue;

                $previousQty = InvoiceItemModel::where('invoice_id', $invoice->id)
                    ->where('product_id', $field['product'])
                    ->value('quantity') ?? 0;

                $newQty = $field['qty'];
                // Adjust stock based on quantity change
                if ($newQty > $previousQty) {
                    $difference = $newQty - $previousQty;
                    if ($loyalty->avl_qty_flag != 'A') {
                        $product->qty = max(0, $product->qty - $difference);
                    } else {
                        $product->qty = $product->qty - $difference;
                    }
                } elseif ($newQty < $previousQty) {
                    $difference = $previousQty - $newQty;
                    $product->qty += $difference;
                }
                $product->save();

                // Update or create invoice item
                $invoiceItem = InvoiceItemModel::updateOrCreate(
                    [
                        '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'],
                        'description' => $field['description'] ?? '',
                    ]
                );

                $productIds[] = $field['product'];

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

            // Remove items that were deleted from the invoice
            InvoiceItemModel::where('invoice_id', $invoice->id)
                ->whereNotIn('product_id', $productIds)
                ->delete();

            DB::commit();

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

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

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

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

            $hasPayments = PaymentsModel::where('invoice_id', $invoice->id)
                ->where('active_flag', 'A')
                ->exists();

            if ($hasPayments) {
                DB::rollBack();
                return redirect()->route('invoice-index')
                    ->with('error', 'Cannot delete invoice: There are active payments linked to this invoice.');
            }

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

                $item->invoiceItemTaxes()->delete();
            });

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

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

            $invoice->delete();

            DB::commit();

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

        } catch (\Exception $e) {
            DB::rollBack();
            \Log::error('Invoice deletion failed: ' . $e->getMessage());

            return back()->with('error', 'An error occurred while deleting the invoice.');
        }
    }


    // Helper method to save client
    // protected function saveClient($request)
    // {
    //     $user = User::where('phone', $request->client_num)->first();

    //     if (!empty($user)) {
    //         $client = ClientModel::where('user_id', $user->id)->first();
    //         return $client->id;
    //     } else {
    //         $randomEmail = Str::random(10) . '@billing.com';
    //         $right = RightsModel::where('rights_type', 'client')->first();
    //         $clientRight = $right ? $right->id : null;

    //         $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'),
    //             'rights_id' => $clientRight,
    //         ]);

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

    //         $allBranchIds = DB::table('branch')->pluck('id');

    //         $insertData = [];

    //         foreach ($allBranchIds as $branchId) {
    //             $insertData[] = [
    //                 'user_id' => $user->id,
    //                 'branch_id' => $branchId,
    //             ];
    //         }
    //         DB::table('branch_user')->insert($insertData);
    //         return $client->id;
    //     }
    // }
    public function savePdf(Request $request)
    {
        return 'pdf generated';
    }

    public function sendInvoice(Request $request)
    {
        $phone = $request->input('phone_number', '919840353040'); // Default test number
        $invoiceNumber = $request->input('invoice_id');
        $amount = $request->input('invoice_amnt');
        if ($phone !== null) {
            $phone = $phone;
        }
        $response = $this->whatsappService->sendWhatsAppMessage($phone, $invoiceNumber, $amount);
        return response()->json($response);
    }

    public function getSingleClient(Request $request)
    {
        $client = ClientModel::findOrFail($request->clientID);
        $dueAmount = $this->dueAmount($client);
        $redeem = LoyaltyTransactionModel::where('client_id', $client->id)->get();

        $earnedPoints = $redeem->where('type', 'earn')->sum('points');
        $redeemedPoints = $redeem->where('type', 'redeem')->sum('points');
        $availablePoints = $earnedPoints - $redeemedPoints;

        return response()->json([
            'client' => $client,
            'earnPoints' => $earnedPoints,
            'redeemPoints' => $redeemedPoints,
            'availablePoints' => $availablePoints,
            'dueAmount' => $dueAmount
        ]);

    }

    public function dueAmount($client)
    {
        $clientInvoices = InvoiceModel::with('payments')->where('client_id', $client->id)
            ->where('oprntl_flag', 'A')
            ->where('branch_id', session('branch_id'))
            ->get();
        $dueAmount = 0;
        if ($clientInvoices->isNotEmpty()) {
            $finalAmount = $clientInvoices->sum('final_amount');
            $paidAmount = $clientInvoices->pluck('payments')->flatten()->sum('amount');

            $dueAmount = max($finalAmount - $paidAmount, 0);
        }
        return $dueAmount;
    }
    public function getInvoiceClient(Request $request)
    {

        $client = ClientModel::findOrFail($request->clientID);

        $transactions = LoyaltyTransactionModel::where('client_id', $client->id)->get();

        $earnedPoints = $transactions
            ->where('type', 'earn')
            ->whereNotIn('reference_invoice', [$request->invoiceID])
            ->sum('points');

        $redeemedPoints = $transactions
            ->where('type', 'redeem')
            ->sum('points');

        $availablePoints = $earnedPoints - $redeemedPoints;

        return response()->json([
            'client' => $client,
            'earnPoints' => $earnedPoints,
            'redeemPoints' => $redeemedPoints,
            'availablePoints' => $availablePoints,
        ]);
    }


}