<?php

namespace App\Http\Controllers;

use App\AccountsPermissions;
use App\BusinessPartner;
use App\Customer;
use App\Employees;
use App\Suppliers;
use App\TransactionAccount;
use App\Voucher;
use App\VouchersUniqueNumber;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Yajra\DataTables\Facades\DataTables;

class VoucherController extends Controller
{
    private const UNITS = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine'];
    private const TEENS = ['Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen'];
    private const TENS = ['Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'];
    private const THOUSANDS = ['Thousand', 'Million', 'Billion', 'Trillion'];

    protected string $module = 'Journal Vouchers';

    public function __construct()
    {
        $module = $this->module;

        $this->middleware("permission:$module list")->only(['index']);
        $this->middleware("permission:$module view")->only(['show']);
        $this->middleware("permission:$module add")->only(['create', 'store']);
        $this->middleware("permission:$module edit")->only(['edit', 'update']);
        $this->middleware("permission:$module delete")->only(['destroy']);
    }

    public function index()
    {
        // $vouchersNumber = VouchersUniqueNumber::with('vouchers')->where('voucher_type', 'Journal Voucher')->get();
        return view('voucher.index');
    }
    // public function index(Request $request)
    // {
    //     // Fetch all vouchers with related data
    //     $vouchers = VouchersUniqueNumber::with(['vouchers' => function ($query) {
    //         $query->select(
    //             'vouchers.*',
    //             'account_title',
    //             'business_partner_type',
    //             'partner_name',
    //             DB::raw('IFNULL(debit, 0) as debit'),
    //             DB::raw('IFNULL(credit, 0) as credit')
    //         );
    //     }])
    //     ->where('voucher_type', 'Journal Voucher')
    //     ->get();

    //     // Filter vouchers based on account permissions in PHP
    //     $filteredVouchers = $vouchers->filter(function ($voucherUnique) {
    //         return $voucherUnique->vouchers->contains(function ($voucher) {
    //             // Ensure to check against existing permissions only
    //             $accountPermission = $voucher->accounts_permissions;
    //             return $accountPermission && $voucher->account_title === $accountPermission->account_name;
    //         });
    //     });
    //     dd($filteredVouchers);

    //     // Return the view with the filtered vouchers data
    //     return view('voucher.index', ['vouchers' => $filteredVouchers]);
    // }



    public function voucher_listing(Request $request)
    {
        // Fetch vouchers with related vouchers and necessary fields
        $vouchers = VouchersUniqueNumber::with(['vouchers' => function ($query) {
            $query->select(
                'vouchers.*',
                'account_title',
                'business_partner_type',
                'partner_name',
                DB::raw('IFNULL(debit, 0) as debit'),
                DB::raw('IFNULL(credit, 0) as credit')
            );
        }])->where('voucher_type', 'Journal Voucher')->get();

        // Return a DataTable instance, but treat each voucher as a new row

        // return DataTables::of($vouchers->flatMap(function ($vouchersUnique) {

        //     return $vouchersUnique->vouchers->map(function ($voucher) use ($vouchersUnique) {

        //         return [
        //             'voucher_number' => $vouchersUnique->voucher_number,
        //             'voucher_date' => date('d F Y', strtotime($voucher->date)),
        //             'debit' => number_format($voucher->debit, 2),
        //             'credit' => number_format($voucher->credit, 2),
        //             'account_title' => $voucher->account_title ?? '', // account_title  name
        //             'bp_type' => $voucher->business_partner_type ?? '', // Business partner type
        //             'bp_name' => $voucher->partner_name ?? '',
        //             'action' => '<a class="btn btn-outline-success btn-sm rounded-pill shadow-sm" '
        //                 . 'title="View Journal Voucher" '
        //                 . 'href="' . route('voucher.view', Crypt::encrypt($voucher->vouchers_unique_number_id)) . '" '
        //                 . 'target="_blank"><i class="fa-solid fa-eye"></i> View</a>'
        //         ];
        //     });
        // }))
        //     ->rawColumns(['action']) // Ensure action column is processed as raw HTML
        //     ->make(true);
        $accountNames = AccountsPermissions::pluck('account_name')->toArray();

        return DataTables::of($vouchers->flatMap(function ($vouchersUnique) use ($accountNames) {
            return $vouchersUnique->vouchers->filter(function ($voucher) use ($accountNames) {
                return in_array($voucher->account_title, $accountNames);
            })->map(function ($voucher) use ($vouchersUnique) {
                return [
                    'voucher_number' => $vouchersUnique->voucher_number,
                    'voucher_date' => date('d F Y', strtotime($voucher->date)),
                    'debit' => number_format($voucher->debit, 2),
                    'credit' => number_format($voucher->credit, 2),
                    'account_title' => $voucher->account_title ?? '', // Transaction account name
                    'bp_type' => $voucher->business_partner_type ?? '', // Business partner type
                    'bp_name' => $voucher->partner_name ?? '',
                    'action' => auth()->user()->can('Journal Vouchers edit')
                        ? '<a class="btn btn-outline-success btn-sm rounded-pill shadow-sm"
        title="View Journal Voucher"
        href="' . route('voucher.view', Crypt::encrypt($voucher->vouchers_unique_number_id)) . '"
        target="_blank"><i class="fa-solid fa-eye"></i> View</a>'
                        : ''
                ];
            });
        }))
            ->rawColumns(['action']) // Ensure action column is processed as raw HTML
            ->make(true);
    }

    public function create()
    {
        // Fetch employees data
        $employees = Employees::all();
        $accounts = TransactionAccount::all();
        return view('voucher.create', compact('employees', 'accounts'));
    }

    public function store(Request $request)
    {
        // Validate the incoming data
        $validate = $request->validate([
            'voucherDate.*' => 'required|date',
            'accountNo.*' => 'required|string',
            'accountName.*' => 'required|string',
            'paymentMode.*' => 'required|string',
            'instrumentAmount.*' => 'nullable|string',
            'netAmount.*' => 'required|numeric',
            'noteRemarks.*' => 'nullable|string',
            'debitAMount.*' => 'nullable|numeric',
            'creditAmount.*' => 'nullable|numeric',
            'businessPartnerType.*' => 'nullable|string',
            'businessPartnerName.*' => 'nullable|string',
            'taxDebitYesNo.*' => 'required|string',
            'transactionAccountId.*' => 'required|string',
            'transactionAccountName.*' => 'required|string',
            'vDescription.*' => 'nullable|string',
        ]);
        // dd($voucherUniqueNumber);
        // Generate a unique journal voucher number (e.g., JV-XXXXX)
        $uniqueVoucherNumber = 'JV-' . str_pad(rand(0, 99999), 5, '0', STR_PAD_LEFT);

        // Create a new VouchersUniqueNumber record
        $voucherUniqueNumber = new VouchersUniqueNumber();
        $voucherUniqueNumber->voucher_type = 'Journal Voucher';
        $voucherUniqueNumber->voucher_number = $uniqueVoucherNumber;
        // dd($request);

        $voucherUniqueNumber->save();  // Save the unique voucher number record first

        // Loop through each row and create a voucher record
        if ($validate) {

            for ($i = 0; $i < count($request->accountNo); $i++) {
                $voucher = new Voucher();
                $voucher->vouchers_unique_number_id = $voucherUniqueNumber->id_vouchers_unique_number;  // Associate with unique voucher number
                $voucher->date = $request->voucherDate[$i];
                $voucher->account_no = $request->accountNo[$i];
                $voucher->account_title = $request->accountName[$i];
                $voucher->payment_mode = $request->paymentMode[$i];
                $voucher->instrument = $request->instrumentAmount[$i];
                $voucher->business_partner_type = $request->business_partner;
                $voucher->partner_name = $request->partner_name;
                // $voucher->partner_id = $request->partner_name;
                $voucher->transaction_acc_no = $request->transaction_account;
                $voucher->transaction_acc_name = $request->transaction_account;
                $voucher->amount = $request->netAmount[$i];
                $voucher->remarks = 'Null';
                $voucher->debit = $request->debitAmount[$i];
                $voucher->credit = $request->creditAmount[$i];
                $voucher->tax_debit = 'No';
                $voucher->desciption = 'Null';
                $voucher->status = 'Posted';
                // Save the voucher
                $voucher->save();
            }
            return redirect()->route('voucher.list')->with('success', 'Vouchers have been created successfully.');
        } else {
            // Return back with validation errors and input data
            return redirect()->back()->with('danger', 'Please fill up the fields.');
        }
    }


    public function view($id)
    {
        $id = Crypt::decrypt($id);
        $voucherDetails = VouchersUniqueNumber::with('vouchers')->where('voucher_type', 'Journal Voucher')->where('id_vouchers_unique_number', $id)->first();
        $accountVouchers = $voucherDetails->vouchers->where('vouchers_unique_number_id', $id);
        $vou_other_detail = $voucherDetails->vouchers->where('vouchers_unique_number_id', $id)->first();
        // dd($vou_other_detail);
        return view('voucher.view', compact('voucherDetails', 'accountVouchers', 'vou_other_detail'));
    }

    public function edit($encryptedId)
    {
        $id = Crypt::decrypt($encryptedId);
        $vouchersNumber = VouchersUniqueNumber::with('vouchers')->where('voucher_type', 'Journal Voucher')->findOrFail($id);
        $voucherSingle = $vouchersNumber->vouchers->first();

        $totalCredit = 0;
        $totalDebit = 0;

        // Loop through each voucher and accumulate the totals
        foreach ($vouchersNumber->vouchers as $voucher) {
            $totalCredit += $voucher->credit; // Sum credit amounts
            $totalDebit += $voucher->debit;   // Sum debit amounts
        }
        $voucherDetails = VouchersUniqueNumber::with('vouchers')->where('voucher_type', 'Journal Voucher')->where('id_vouchers_unique_number', $id)->first();

        $vou_other_detail = $voucherDetails->vouchers->where('vouchers_unique_number_id', $id)->first();

        // dd($vou_other_detail);
        // Fetch employees and accounts for the form
        $employees = Employees::all();
        $accounts = TransactionAccount::all();

        return view('voucher.edit', compact('vou_other_detail', 'totalCredit', 'totalDebit', 'employees', 'accounts', 'vouchersNumber', 'voucherSingle'));
    }


    public function update(Request $request, $encryptedId)
    {
        // Validate the incoming data
        $validatedData = $request->validate([
            'voucherDate.*' => 'required|date',
            'accountNo.*' => 'required|string',
            'accountName.*' => 'required|string',
            'paymentMode.*' => 'required|string',
            'instrumentAmount.*' => 'nullable|string',
            'netAmount.*' => 'required|numeric',
            'noteRemarks.*' => 'nullable|string',
            'debitAmount.*' => 'nullable|numeric',
            'creditAmount.*' => 'nullable|numeric',
            'partner_name.*' => 'required|string',
            'business_partner.*' => 'required|string',
            'taxDebitYesNo.*' => 'required|string',
            'vDescription.*' => 'nullable|string',
        ]);

        // Decrypt the ID
        $id = Crypt::decrypt($encryptedId);

        // Find the voucher record by the decrypted ID
        $voucherUniqueNumber = VouchersUniqueNumber::with('vouchers')->findOrFail($id);

        // Check for deleted vouchers
        $deletedVoucherIds = explode(',', $request->deletedVouchers);
        if (!empty($deletedVoucherIds)) {
            Voucher::whereIn('id_vouchers', $deletedVoucherIds)->delete();
        }

        // Loop through each existing voucher and update its data
        foreach ($voucherUniqueNumber->vouchers as $index => $voucher) {
            $voucher->update([
                'date' => $validatedData['voucherDate'][$index] ?? $voucher->date,
                'account_no' => $validatedData['accountNo'][$index] ?? $voucher->account_no,
                'account_title' => $validatedData['accountName'][$index] ?? $voucher->account_title,
                'payment_mode' => $validatedData['paymentMode'][$index] ?? null,
                'instrument' => $validatedData['instrumentAmount'][$index] ?? null,
                'amount' => $validatedData['netAmount'][$index] ?? null,
                'remarks' => $validatedData['noteRemarks'][$index] ?? null,
                'debit' => $validatedData['debitAmount'][$index] ?? null,
                'credit' => $validatedData['creditAmount'][$index] ?? null,
                $voucher->partner_name = $request->partner_name,
                $voucher->business_partner_type = $request->business_partner,

                'tax_debit' => 'Null',
                'desciption' => $validatedData['vDescription'][$index] ?? null,
            ]);
        }

        // Add new vouchers if they exist in the request
        for ($i = count($voucherUniqueNumber->vouchers); $i < count($request->accountNo); $i++) {
            $voucher = new Voucher();
            $voucher->vouchers_unique_number_id = $voucherUniqueNumber->id_vouchers_unique_number;  // Associate with unique voucher number
            $voucher->date = $request->voucherDate[$i];
            $voucher->account_no = $request->accountNo[$i];
            $voucher->account_title = $request->accountName[$i];
            $voucher->payment_mode = $request->paymentMode[$i];
            $voucher->instrument = $request->instrumentAmount[$i] ?? null;
            $voucher->amount = $request->netAmount[$i];
            $voucher->remarks = $request->noteRemarks[$i] ?? 'Null';
            $voucher->debit = $request->debitAmount[$i] ?? null;
            $voucher->credit = $request->creditAmount[$i] ?? null;
            $voucher->business_partner_type = $request->business_partner;
            $voucher->partner_name = $request->partner_name;
            $voucher->tax_debit = $request->taxDebitYesNo[$i] ?? 'No';
            $voucher->desciption = 'Null';
            $voucher->status = 'Posted';
            // dd($voucher);
            // Save the voucher
            $voucher->save();
        }

        // Redirect back with success message
        return redirect()->back()->with('success', 'Voucher updated successfully.');
    }




    // public function print($id)
    // {
    //     $id = Crypt::decrypt($id);
    //     $vouchersNumber = VouchersUniqueNumber::with('vouchers')->where('voucher_type', 'Journal Voucher')->where('id_vouchers_unique_number', $id)->first();
    //     $voucherSingle = $vouchersNumber->vouchers->first();
    //     return view('voucher.print', compact('vouchersNumber', 'voucherSingle'));
    // }

    // In VoucherController.php
    public function print($id)
    {
        $id = Crypt::decrypt($id);
        $voucherNumber = VouchersUniqueNumber::with('vouchers')->where('voucher_type', 'Journal Voucher')->where('id_vouchers_unique_number', $id)->first();
        // $voucherNumber = VouchersUniqueNumber::with('vouchers')->findOrFail(Crypt::decrypt($id));

        return view('voucher.print', compact('voucherNumber'));
    }

    public function getPartnerData(Request $request)
    {
        $type = $request->get('type');

        if ($type === 'employee') {
            $data = Employees::pluck('employee_name', 'id_employee'); // Adjust fields as necessary
        } elseif ($type === 'customer') {
            $data = Customer::pluck('customer_name', 'id_customers'); // Adjust fields as necessary
        } elseif ($type === 'suppliers') {
            $data = Suppliers::pluck('supplier_name', 'id_supplier'); // Adjust fields as necessary
        } else {
            $data = []; // Handle other types later if necessary
        }

        return response()->json($data);
    }

    public function saveVendor(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
        ]);

        // Save the new vendor to the business_partner table
        $vendor = new BusinessPartner();
        $vendor->name = $request->name;
        $vendor->save();

        // Return a JSON response with success and the vendor ID
        return response()->json([
            'success' => true,
            'vendor_id' => $vendor->id_business_partner
        ]);
    }

    public function getTransactionAccounts(Request $request)
    {
        $type = $request->get('type');

        // Validate the type to ensure it's either 'cash' or 'bank'
        if (!in_array($type, ['cash', 'bank'])) {
            return response()->json([]);
        }

        // Fetch accounts based on the account type
        $accounts = TransactionAccount::where('account_type', $type)->pluck('transaction_account_name', 'id_transaction_account');

        return response()->json($accounts);
    }

    private function convertNumber($number)
    {
        if ($number == 0) {
            return 'Zero';
        }

        $number = (int)$number;
        $result = '';

        if ($number < 10) {
            $result = self::UNITS[$number];
        } elseif ($number < 20) {
            $result = self::TEENS[$number - 11];
        } elseif ($number < 100) {
            $result = self::TENS[intdiv($number, 10) - 2];
            if (($number % 10) > 0) {
                $result .= '-' . self::UNITS[$number % 10];
            }
        } elseif ($number < 1000) {
            $result = self::UNITS[intdiv($number, 100)] . ' Hundred';
            if (($number % 100) > 0) {
                $result .= ' and ' . $this->convertNumber($number % 100);
            }
        } elseif ($number < 1000000) {
            $result = $this->convertNumber(intdiv($number, 1000)) . ' Thousand';
            if (($number % 1000) > 0) {
                $result .= ' ' . $this->convertNumber($number % 1000);
            }
        } else {
            // Handle millions, billions, etc.
            foreach (self::THOUSANDS as $index => $word) {
                $divider = pow(1000, $index + 1);
                if ($number >= $divider) {
                    $result = $this->convertNumber(intdiv($number, $divider)) . ' ' . $word;
                    if (($number % $divider) > 0) {
                        $result .= ' ' . $this->convertNumber($number % $divider);
                    }
                    break;
                }
            }
        }

        return $result;
    }
}
