<?php

namespace App\Http\Controllers\Accounting;

use App\Classes\EditLogHistory;
use Carbon\Carbon;
use App\Models\Expense;
use App\Models\Employee;
use App\Models\ExpenseHead;
use App\Models\FundTransfer;
use App\Models\BankTransfar;
use App\Models\Banking;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Models\UserAccounting;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;

class ExpenseController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:expense-entry|expense-section', ['only' => ['index', 'show']]);
        $this->middleware('permission:expense-section', ['only' => ['create', 'store']]);
        $this->middleware('permission:expense-section', ['only' => ['edit', 'update','expenseApprove']]);
    }

    public function index()
    {
        // Don't load expenses here - DataTables will load them via AJAX
        $data = [
            'expenseHead'   => ExpenseHead::where('id', '!=', 6)->get(),
            'employes'      => Employee::where('status', 'active')->get()
        ];

        return view('accounts.expense.index', $data);
    }

    public function getExpensesData(Request $request)
    {
        // Get DataTables parameters
        $draw = $request->get('draw');
        $start = $request->get('start', 0);
        $length = $request->get('length', 10);
        $searchValue = $request->get('search')['value'] ?? '';

        // Column mapping for ordering (accounting for checkbox column if enabled)
        $checkboxOffset = checkSettings('expense_approve_multiple') == 'enable' ? 1 : 0;
        $columns = ['id', 'status', 'name', 'expenseHead', 'employee_id', 'invoice_number', 'date', 'amount', 'attach_document', 'description', 'created_by'];

        $orderColumn = isset($request->get('order')[0]['column']) ? $request->get('order')[0]['column'] : ($checkboxOffset ? 1 : 0);
        $orderDir = $request->get('order')[0]['dir'] ?? 'desc';
        $orderBy = isset($columns[$orderColumn - $checkboxOffset]) ? $columns[$orderColumn - $checkboxOffset] : 'id';

        // Build base query with eager loading for total count
        $baseQuery = Expense::query();
        if (!auth()->user()->hasPermissionTo('all-expense-show')) {
            $baseQuery->where('created_by', auth()->user()->id);
        }
        $recordsTotal = $baseQuery->count();

        // Build filtered query
        $query = Expense::with(['head', 'employee', 'admin', 'bankAccount']);

        // Apply permission filter
        if (!auth()->user()->hasPermissionTo('all-expense-show')) {
            $query->where('created_by', auth()->user()->id);
        }

        // Apply search filter
        if (!empty($searchValue)) {
            $query->where(function($q) use ($searchValue) {
                $q->where('name', 'like', '%' . $searchValue . '%')
                  ->orWhere('invoice_number', 'like', '%' . $searchValue . '%')
                  ->orWhere('amount', 'like', '%' . $searchValue . '%')
                  ->orWhere('description', 'like', '%' . $searchValue . '%')
                  ->orWhereHas('head', function($q) use ($searchValue) {
                      $q->where('name', 'like', '%' . $searchValue . '%');
                  })
                  ->orWhereHas('employee', function($q) use ($searchValue) {
                      $q->where('name', 'like', '%' . $searchValue . '%');
                  })
                  ->orWhereHas('admin', function($q) use ($searchValue) {
                      $q->where('name', 'like', '%' . $searchValue . '%');
                  });
            });
        }

        // Get filtered count
        $recordsFiltered = $query->count();

        // Apply ordering
        if ($orderBy === 'expenseHead') {
            $query->join('expense_heads', 'expenses.expenseHead', '=', 'expense_heads.id')
                  ->orderBy('expense_heads.name', $orderDir)
                  ->select('expenses.*');
        } elseif ($orderBy === 'employee_id') {
            $query->leftJoin('employees', 'expenses.employee_id', '=', 'employees.id')
                  ->orderBy('employees.name', $orderDir)
                  ->select('expenses.*');
        } elseif ($orderBy === 'created_by') {
            $query->join('users', 'expenses.created_by', '=', 'users.id')
                  ->orderBy('users.name', $orderDir)
                  ->select('expenses.*');
        } else {
            $query->orderBy($orderBy, $orderDir);
        }

        // Apply pagination
        $expenses = $query->skip($start)->take($length)->get();

        // Format data for DataTables
        $data = [];
        foreach ($expenses as $row) {
            $isS3 = checkSettings('store_image_to_s3') === 'enable';
            $imgUrl = !empty($row->attach_document)
                ? ($isS3 ? $row->attach_document : asset('storage/expenseDocument/' . $row->attach_document))
                : null;

            $documentHtml = !empty($row->attach_document)
                ? '<img src="' . $imgUrl . '" width="auto" height="100" alt="Document">'
                : '<p style="margin-inline: 10px">No File</p>';

            $statusBadge = $row->status == 'pending'
                ? '<span class="badge badge-danger">Pending</span>'
                : '<span class="badge badge-success">Approved</span>';

            // Generate action buttons HTML
            $csrfToken = csrf_token();
            $actionHtml = '<div class="dropdown">
                <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton' . $row->id . '" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Action</button>
                <div class="dropdown-menu" aria-labelledby="dropdownMenuButton' . $row->id . '">';

            if (auth()->user()->can('expense-section') && !in_array($row->head->id ?? 0, [6])) {
                if ($row->status != 'approved') {
                    if (auth()->user()->can('expense-approve')) {
                        $actionHtml .= '<form action="' . route('expense-approve', $row) . '" method="POST"><input type="hidden" name="_token" value="' . $csrfToken . '"><input type="hidden" name="_method" value="POST"><button onclick="return confirm(\'Are you sure you want to Approve?\');" class="dropdown-item">Approve</button></form>';
                    }
                    $actionHtml .= '<a href="' . route('expense.edit', $row->id) . '" class="dropdown-item"><i class="fa fa-pencil-square-o"></i> Edit</a>';
                    $actionHtml .= '<a href="' . route('editLog-history', ['id' => $row->id, 'type' => 'Expense']) . '" class="dropdown-item"><i class="fa fa-pencil-square-o"></i> History</a>';
                    $actionHtml .= '<form action="' . route('expense.destroy', $row) . '" method="POST"><input type="hidden" name="_token" value="' . $csrfToken . '"><input type="hidden" name="_method" value="DELETE"><button onclick="return confirm(\'Are you sure you want to Delete?\');" class="dropdown-item">Delete</button></form>';
                } else {
                    if (auth()->user()->can('expense_destroy')) {
                        $actionHtml .= '<form action="' . route('expense.destroy', $row) . '" method="POST"><input type="hidden" name="_token" value="' . $csrfToken . '"><input type="hidden" name="_method" value="DELETE"><button onclick="return confirm(\'Are you sure you want to Delete?\');" class="dropdown-item">Delete</button></form>';
                    } else {
                        $actionHtml .= '<span class="dropdown-item">No Action available</span>';
                    }
                }
            }
            $actionHtml .= '</div></div>';

            // Bank account information
            $bankAccountInfo = '';
            if ($row->bankAccount) {
                $bankAccountInfo = $row->bankAccount->account_name . ' - ' . $row->bankAccount->bank_name;
            } 

            $rowData = [
                'id' => $row->id,
                'status' => $statusBadge,
                'name' => $row->name,
                'expense_head' => $row->head->name ?? '',
                'employee' => $row->employee->name ?? '',
                'invoice_number' => $row->invoice_number,
                'date' => date('d/m/Y', strtotime($row->date)),
                'amount' => $row->amount,
                'bank_account' => $bankAccountInfo,
                'document' => $documentHtml,
                'description' => $row->description,
                'created_by' => $row->admin->name ?? '',
                'action' => $actionHtml,
            ];

            // Add checkbox column if enabled
            if (checkSettings('expense_approve_multiple') == 'enable') {
                $rowData = array_merge(['checkbox' => ''], $rowData);
            }

            $data[] = $rowData;
        }

        return response()->json([
            'draw' => intval($draw),
            'recordsTotal' => $recordsTotal,
            'recordsFiltered' => $recordsFiltered,
            'data' => $data
        ]);
    }


    public function create()
    {
        $expenseHead = ExpenseHead::all();
        $employes = Employee::where('status','active')->get();

        return view('accounts.expense.create', compact('expenseHead','employes'));
    }


    public function store(Request $request)
    {
        $request->validate([
            'attach_document' => 'mimes:jpeg,jpg,png,webp,gif,pdf|max:10240',
            'amount'          => 'required',
        ]);

        // dd($request->all());

        DB::beginTransaction();
        try {
            if(!empty($request->employee)){
               $employee =  Employee::find($request->employee);
               $note = $request->description;
            }else{
                $note = $request->description;
            }


            $expense = new Expense();

            $expense->name = $request->name;
            $expense->invoice_number = $request->invoice_number;
            $expense->date = Carbon::parse($request->date);
            $expense->amount = $request->amount;
            $expense->description =  $note;
            $expense->expenseHead = $request->expenseHead;
            $expense->created_by = auth()->user()->id;
            $expense->employee_id = $request->employee;
            $expense->bank_account_id = !empty($request->bank_account_id) ? $request->bank_account_id : null;


            if ($request->attach_document != null) {
               // for s3 upload
               if (checkSettings('store_image_to_s3') === 'enable') {
                    $fileName = time() . '.' . $request->attach_document->extension();
                    $path = 'expenseDocument/' . $fileName;

                    // Store to S3
                    $request->attach_document->storeAs('expenseDocument', $fileName, 's3');

                    // Optionally make public (if needed)
                    Storage::disk('s3')->setVisibility($path, 'public');

                    // ✅ Save full URL or path
                    $expense->attach_document = Storage::disk('s3')->url($path); // or just $path
                } else {
                    $fileName = time() . '.' . $request->attach_document->extension();
                    $request->attach_document->move(storage_path('app/public/expenseDocument'), $fileName);
                    $expense->attach_document = $fileName;
                }



            }
            $expense->save();

            DB::commit();

            Toastr::success('success','Expense Successfully Submitted',['success' => 'alert alert-success']);
            return redirect()->back();


        } catch (\Throwable $th) {
            //throw $th;
            dd($th);

            DB::rollBack();
        }



        return redirect()->route('expense.index');
    }


    public function expenseApprove(request $request,$id)
    {

        DB::beginTransaction();

        try {

            $expense = Expense::find($id);

            // dd($expense->fund_transfer_id);
            if($expense->user_accounting_id != null ){

                $user_accounting = UserAccounting::where('id',$expense->user_accounting_id)->update([
                    'received_amount'  =>  0,
                    'paid_amount'      => $expense->amount,
                    'actions'          =>  $expense->description.' approved by '.auth()->user()->name,
                    'comments'         => null,
                    'user_id'          => $expense->created_by,

                ]);

            }else{
                $user_accounting = UserAccounting::create([
                    'received_amount'  =>  0,
                    'paid_amount'      => $expense->amount,
                    'actions'          =>  $expense->description.' approved by '.auth()->user()->name,
                    'comments'         => null,
                    'user_id'          => $expense->created_by,

                ]);
                $expense->user_accounting_id = $user_accounting->id;
            }


            $expense->status = 'approved';
            $expense->save();

            // Check if bank account is selected and withdraw amount on approval
            if ($expense->bank_account_id) {
                // Check if withdrawal already exists for this expense
                $existingWithdrawal = BankTransfar::where('description', 'like', '%Expense [ID:' . $expense->id . ']%')
                    ->whereNotNull('withdraw_amount')
                    ->first();

                if (!$existingWithdrawal) {
                    // Check bank balance before withdrawal
                    $banking = Banking::find($expense->bank_account_id);
                    if ($banking) {
                        $total_deposit = BankTransfar::where('account_id', $expense->bank_account_id)->sum('diposit_amount');
                        $total_withdrawal = BankTransfar::where('account_id', $expense->bank_account_id)->sum('withdraw_amount');
                        $balance = $banking->opening_balance + $total_deposit - $total_withdrawal;

                        if ($expense->amount > $balance) {
                            DB::rollBack();
                            Toastr::error('Withdraw Amount is greater than Bank Balance', 'Error');
                            return redirect()->back();
                        }

                        // Withdraw from bank account
                        $bankWithdrawal = new BankTransfar();
                        $bankWithdrawal->account_id = $expense->bank_account_id;
                        $bankWithdrawal->withdraw_amount = $expense->amount;
                        $bankWithdrawal->description = 'Expense [ID:' . $expense->id . ']: ' . $expense->name . ' - ' . ($expense->description ?? 'Expense');
                        $bankWithdrawal->by = auth()->user()->name ?? 'System';
                        $bankWithdrawal->save();
                    }
                }
            }

            DB::commit();



            Toastr::success('success','Expense Approved',['success' => 'alert alert-success']);
            return redirect()->back();


        } catch (\Throwable $th) {

            DB::rollBack();
        }
    }

    public function expenseApproveMultiple(Request $request)
    {
        $ids = $request->ids;
        foreach($ids as $id){
            $this->expenseApprove($request,$id);
        }
        return response()->json(['success' => 'Expenses approved successfully']);
    }


    public function show(Expense $expense)
    {
        // return view('expenseReport.index');
    }


    public function edit($id)
    {
        $expense = Expense::with('head')->find($id);

        if($expense->head->name == "BandWith Buy"){
            Toastr::error("THis expense can not edit from here");
            return redirect()->back();
        }
        $data = [
            'model' => $expense,
            'expenseHead' => ExpenseHead::all(),
            'title' => 'Expense',
            'employees' => Employee::where('status','active')->get()
        ];
        // dd($data);
        return view('accounts.expense.edit', $data);
    }


    public function update(Request $request)
    {
        $type = 'Expense';
        $old_info = Expense::where('id', $request->id)->first();

        $expense = Expense::find($request->id);
        $expense->name = $request->name;
        $expense->invoice_number = $request->invoice_number;
        $expense->employee_id = $request->employee_id;
        $expense->date = Carbon::parse($request->date)->format('Y-m-d 00:00:00');
        $expense->amount = $request->amount;
        $expense->description = $request->description;
        $expense->expenseHead = $request->expenseHead;
        // $expense->created_by = auth()->user()->id;


        if ($request->attach_document != null) {
            // for s3 upload
            if (checkSettings('store_image_to_s3') === 'enable') {
              if ($expense->attach_document != null) {
                    // Extract the path after the domain
                    $parsedUrl = parse_url($expense->attach_document);
                    $oldPath = ltrim($parsedUrl['path'], '/'); // remove leading slash

                    // Delete the old file from S3
                    Storage::disk('s3')->delete($oldPath);
                }

                $fileName = time() . '.' . $request->attach_document->extension();
                $path = 'expenseDocument/' . $fileName;

                // Store the new file to S3
                $request->attach_document->storeAs('expenseDocument', $fileName, 's3');

                // Make it public (optional)
                Storage::disk('s3')->setVisibility($path, 'public');

                // Save the new file URL
                $expense->attach_document = Storage::disk('s3')->url($path);
            } else {
                  File::delete(public_path('storage/expenseDocument/' . $expense->attach_document));
                $fileName = time() . '.' . $request->attach_document->extension();
                $request->attach_document->move(storage_path('app/public/expenseDocument'), $fileName);
                $expense->attach_document = $fileName;
            }



        }

        $expense->save();

        $new_info = Expense::find($expense->id);
        (new EditLogHistory)->editLogSave($expense, $type, $old_info, $new_info);
        Toastr::success('success','Expense Updated Successfully',['success' => 'alert alert-success']);

        return redirect()->back();
    }


    public function destroy(Expense $expense)
    {
        Db::beginTransaction();
        try{
            $fund_transfer = FundTransfer::where('id',$expense->fund_transfer_id)->delete();
            // refund in user accounting
            if($expense->status == 'approved'){
                if($expense->user_accounting_id != null ){
                    $user_accounting = UserAccounting::where('id',$expense->user_accounting_id)->update([
                        'received_amount'  => 0,
                        'paid_amount'      => 0,
                        'comments'         => 'restored due to expense deletion',
                    ]);
                }
            }

            $expense->delete();
            DB::commit();
            Toastr::success('success','Expense Deleted',['success' => 'alert alert-success']);
            return redirect()->route('expense.index');
        }catch(\Throwable $th){
            DB::rollBack();
            Toastr::error('error','Something Went Wrong',['error' => 'alert alert-danger']);
        }

    }

    public function expenseReport()
    {
        // dd('hello');
        $start = Carbon::now()->today()->firstOfMonth();;

        // dd($start);
        $end = today();
        return view('accounts.expenseReport.index', [
            'start' => $start,
            'end'   => $end,
            'expenseHeads' => ExpenseHead::all(),
        ]);
    }

    public function expenseSearchResult(Request $request)
    {


        $start = Carbon::parse($request->from_date)->format('Y-m-d 00:00:00');
        $end = Carbon::parse($request->to_date)->format('Y-m-d 23:59:59');
        if($request->expenseHead == 'all'){
            $expenses = Expense::whereBetween('date', [$start, $end])->orderBy('id','DESC')->get();
        }else{
            $expenses = Expense::whereBetween('date', [$start, $end])->where('expenseHead',$request->expenseHead)->orderBy('id','DESC')->get();
        }

        $data = [
            'expenses' => $expenses,
        ];
        return view('accounts.expenseReport.result',$data);


    }

    public function changeExpenseDate()
    {
        $expenses = Expense::wherebetween('date', ['2022-12-19 00:00:00', '2022-12-31 23:59:59'])->get();
        foreach ($expenses as $expense) {
            $expense->date = Carbon::parse($expense->date)->subMonth()->format('Y-m-d 00:00:00');
            $expense->save();
        }
        Toastr::success('success','Expense Date Changed',['success' => 'alert alert-success']);
        return redirect()->back();
    }
}
