<?php

namespace Modules\Travel\Repositories;

use Carbon\Carbon;
use App\Models\Upload;
use Illuminate\Support\Facades\DB;
use Modules\Travel\Entities\TravelExpense;
use App\Helpers\CoreApp\Traits\FileHandler;
use Modules\Travel\Entities\TravelExpenseLog;

class TravelExpenseRepository
{
    use FileHandler;

    function fields()
    {
        return [
            _trans('common.ID'),
            _trans('common.Employee'),
            _trans('common.Date'),
            _trans('common.Mode Of Transportation'),
            _trans('common.Amount'),
            _trans('common.Rating'),
            _trans('common.Action')
        ];
    }

    function table($request, $plan_id)
    {
        $data   = TravelExpense::query()
                ->where('company_id', auth()->user()->company_id)
                ->where('travel_plan_id', $plan_id)
                ->when(request('search'), function ($q) {
                    $search = request('search');
                    $q->where(function ($q) use ($search) {
                        $q->whereHas('employee', function ($q) use ($search) {
                            $q->where('name', 'like', '%' . $search . '%');
                        });
                    });
                })
                ->when(filled(request('from')) && filled(request('to')), function ($q) {
                    $q->whereBetween('date', [request('from'), request('to')]);
                })
                ->when(!isAdminOrHr(), fn ($q) => $q->whereIn("employee_id", getRelatedUserIds()))
                ->latest('id')
                ->paginate($request->limit ?? 2);

            return [
                'data' => $data->map(function ($data) use ($plan_id) {
                    $action_button = '';

                    if (hasPermission('travel_expense_read')) {
                        $action_button .= '<a href="' . route('travel.plans.expenses.show', ['id' => $data->id, 'plan_id' => $plan_id]) . '" class="dropdown-item"> ' . _trans('common.View') . ' </a>';
                    }
                    
                    if ($data->status_id == 2) {

                        if (hasPermission('travel_expense_update')) {
                            $action_button .= '<a href="' . route('travel.plans.expenses.edit', ['id' => $data->id, 'plan_id' => $plan_id]) . '" class="dropdown-item"> ' . _trans('common.Edit') . ' </a>';
                        }

                        if (hasPermission('travel_expense_approve')) {
                            $totalAmount = trim(showAmount($data->total_amount));
                            $approve = "approveExpense('" . $data->id . "', '" . $totalAmount . "')";
                            $action_button .= '<button onclick="' . htmlspecialchars($approve) . '" type="button" class="dropdown-item">
                                                ' . _trans('common.Approve') . '
                                            </button>';
                        }
                    }

                    if (hasPermission('travel_expense_delete')) {
                        $action_button .= actionButton(_trans('common.Delete'), '__globalDelete(' . $data->id . ', `travel/plans/expenses/delete/`)', 'delete');
                    }

                    $button = ' <div class="dropdown dropdown-action">
                                    <button type="button" class="btn-dropdown" data-bs-toggle="dropdown"
                                        aria-expanded="false">
                                        <i class="fa-solid fa-ellipsis"></i>
                                    </button>
                                    <ul class="dropdown-menu dropdown-menu-end">
                                    ' . $action_button . '
                                    </ul>
                                </div>';


                    $amount =  '<div class="d-flex flex-column gap-0">
                                    <div class="d-flex align-items-start gap-3">
                                        <span class="w-50">' . _trans("common.Total Amount") . '</span>
                                        <span>: ' . showAmount($data->total_amount) . '</span>
                                    </div>
                                    <div class="d-flex align-items-start gap-3">
                                        <span class="w-50">' . _trans("common.Approved Amount") . '</span>
                                        <span>: ' . showAmount($data->approval_amount) . '</span>
                                    </div>
                                </div>';
                                   
                    $rating = '';
                    for ($i = 1; $i <= 5; $i++) {
                        $fillColor = $i <= $data->rating_of_travel_experience ? 'text-warning' : '';

                        $rating .= '<i class="las la-star ' . $fillColor . '"></i>';
                    }

                    return [
                        'id' => $data->id,
                        'employee' => $data->employee->name,
                        'date' => $data->date,
                        'mode_of_transportation' => $data->mode_of_transportation ?? _trans("common.N/A"),
                        'amount' => $amount,
                        'rating' => $rating,
                        'action'   => $button
                    ];
                }),
                'pagination' => [
                    'total' => $data->total(),
                    'count' => $data->count(),
                    'per_page' => $data->perPage(),
                    'current_page' => $data->currentPage(),
                    'total_pages' => $data->lastPage(),
                    'pagination_html' =>  $data->links('backend.pagination.custom')->toHtml(),
                ],
            ];
    }
    
    public function storeTravelExpense($request, $plan_id)
    {
        DB::beginTransaction();

        try {
            $travelExpense                              = new TravelExpense();

            $travelExpense->travel_plan_id              = $plan_id;
            $travelExpense->employee_id                 = auth()->id();
            $travelExpense->date                        = Carbon::parse($request->date)->format('Y-m-d');
            $travelExpense->mode_of_transportation      = $request->mode_of_transportation;
            $travelExpense->rating_of_travel_experience = $request->rating ?? $request->rating_of_travel_experience;

            $amounts = array_map('floatval', $request->amount ?? []);
            $totalAmount = array_sum($amounts) ?? 0;

            $travelExpense->total_amount                = $totalAmount;
            $travelExpense->request_amount              = $totalAmount;
            $travelExpense->status_id                   = 2;
            $travelExpense->company_id                  = auth()->user()->company_id;
            $travelExpense->branch_id                   = getCurrentBranch();
            $travelExpense->created_by                  = auth()->id();
            $travelExpense->save();
    
            $this->storeTravelExpenseLogs($request, $travelExpense);
    
            DB::commit();

            return $travelExpense;
        } catch (\Throwable $th) {
            DB::rollBack();
        }
    }

    public function storeTravelExpenseLogs($request, $travelExpense)
    {
        foreach ($request->expense_category_id ?? [] as $key => $expense_category_id) {
            if ($request->amount[$key]) {

                if (@$request->file_id[$key]) {
                    $file_id = $request->file_id[$key];
                } elseif (@$request->file[$key]) {
                    $file_id = $request->file[$key] ? $this->uploadImage($request->file[$key], 'uploads/travel/expense/file')->id : null;
                } else {
                    $file_id = null;
                }

                $travelExpenseLog                      = new TravelExpenseLog();
                $travelExpenseLog->travel_expense_id   = $travelExpense->id;
                $travelExpenseLog->expense_category_id = $expense_category_id;
                $travelExpenseLog->title               = $request->title[$key];
                $travelExpenseLog->amount              = $request->amount[$key];
                $travelExpenseLog->file_id             = $file_id;
                $travelExpenseLog->remark              = @$request->remark[$key] ?? null;
                $travelExpenseLog->company_id          = auth()->user()->company_id;
                $travelExpenseLog->branch_id           = getCurrentBranch();
                $travelExpenseLog->created_by          = auth()->id();

                $travelExpenseLog->save();
            }
        }
    }

    public function updateTravelExpense($request, $plan_id, $id)
    {
        DB::beginTransaction();

        try {
            $travelExpense                              = TravelExpense::find($id);
            $travelExpense->date                        = Carbon::parse($request->date)->format('Y-m-d');
            $travelExpense->mode_of_transportation      = $request->mode_of_transportation;
            $travelExpense->rating_of_travel_experience = $request->rating ?? $request->rating_of_travel_experience;

            $amounts = array_map('floatval', $request->amount ?? []);
            $totalAmount = array_sum($amounts) ?? 0;

            $travelExpense->total_amount                = $totalAmount;
            $travelExpense->request_amount              = $totalAmount;
            $travelExpense->updated_by                  = auth()->id();

            $travelExpense->save();
        
            if ($request->expectsJson()) {
                $this->updateOrCreateTravelExpenseLogs($request, $travelExpense);
            } else {
                $this->updateTravelExpenseLogs($request, $travelExpense);
            }

            DB::commit();

            return $travelExpense;
        } catch (\Throwable $th) {
            DB::rollBack();
        }
    }

    public function updateOrCreateTravelExpenseLogs($request, $travelExpense)
    {
        foreach ($request->expense_category_id ?? [] as $key => $expense_category_id) {
            if ($request->amount[$key]) {

                $travelExpenseLog   = TravelExpenseLog::where([
                                        'travel_expense_id' => $travelExpense->id,
                                        'expense_category_id' => $expense_category_id,
                                    ])->first();

                if (@$request->file_id[$key]) {

                    if ($travelExpenseLog) {
                        $upload_id = $travelExpenseLog->file_id;
        
                        $travelExpenseLog->file_id = null;
                        $travelExpenseLog->save();
            
                        if (file_exists(asset_path($upload_id))) {
                            unlink(asset_path($upload_id));
                        }
            
                        Upload::destroy($upload_id);
                    }

                    $file_id = $request->file_id[$key];
                } else {
                    $file_id = @$travelExpenseLog->file_id ?? null;
                }

                TravelExpenseLog::updateOrCreate([
                    'travel_expense_id' => $travelExpense->id,
                    'expense_category_id' => $expense_category_id,
                ], [
                    'amount' => $travelExpense->id,
                    'file_id' => $file_id,
                    'remark' => @$request->remark[$key] ?? null,
                    'company_id' => auth()->user()->company_id,
                    'branch_id' => getCurrentBranch(),
                    'created_by' => auth()->id(),
                    'updated_by' => auth()->id(),
                ]);
            }
        }
    }

    public function updateTravelExpenseLogs($request, $travelExpense)
    {
        $travelExpenseLogIds = [];

        foreach ($request->expense_category_id ?? [] as $key => $expense_category_id) {

            if ($request->travel_expense_log_id[$key]) {

                $travelExpenseLog = TravelExpenseLog::find($request->travel_expense_log_id[$key]);

                if (@$request->file[$key]) {
                    $upload_id = $travelExpenseLog->file_id;
        
                    $travelExpenseLog->file_id = null;
                    $travelExpenseLog->save();
        
                    if (file_exists(asset_path($upload_id))) {
                        unlink(asset_path($upload_id));
                    }
        
                    Upload::destroy($upload_id);
                }

                $travelExpenseLog->title      = $request->title[$key];
                $travelExpenseLog->amount     = $request->amount[$key];
                $travelExpenseLog->file_id    = @$request->file[$key] ? $this->uploadImage($request->file[$key], 'uploads/travel/expense/file')->id : $travelExpenseLog->file_id;
                $travelExpenseLog->remark     = $request->remark[$key];
                $travelExpenseLog->updated_by = auth()->id();

                $travelExpenseLog->save();

                $travelExpenseLogIds[] = $travelExpenseLog->id;

            } elseif (!$request->travel_expense_log_id[$key] && $request->amount[$key]) {

                if (@$request->file_id[$key]) {
                    $file_id = $request->file_id[$key];
                } elseif (@$request->file[$key]) {
                    $file_id = $request->file[$key] ? $this->uploadImage($request->file[$key], 'uploads/travel/expense/file')->id : null;
                } else {
                    $file_id = null;
                }

                $travelExpenseLog                      = new TravelExpenseLog();
                $travelExpenseLog->travel_expense_id   = $travelExpense->id;
                $travelExpenseLog->expense_category_id = $expense_category_id;
                $travelExpenseLog->title               = $request->title[$key];
                $travelExpenseLog->amount              = $request->amount[$key];
                $travelExpenseLog->file_id             = $file_id;
                $travelExpenseLog->remark              = $request->remark[$key];
                $travelExpenseLog->created_by          = auth()->id();

                $travelExpenseLog->save();

                $travelExpenseLogIds[] = $travelExpenseLog->id;
            }
        }

        $this->deleteTravelExpenseLogs($travelExpense, $travelExpenseLogIds);
    }

    protected function deleteTravelExpenseLogs($travelExpense, $travelExpenseLogIds)
    {
        $deletableLogs = TravelExpenseLog::where('travel_expense_id', $travelExpense->id)->whereNotIn('id', $travelExpenseLogIds)->get();

        foreach($deletableLogs ?? [] as $log)
        {
            if ($log->file_id) {
                $upload_id = $log->file_id;
    
                $log->file_id = null;
                $log->save();
    
                if (file_exists(asset_path($upload_id))) {
                    unlink(asset_path($upload_id));
                }
    
                Upload::destroy($upload_id);
            }

            $log->delete();
        }
    }

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

        try {
            $travelExpense = TravelExpense::with('travelExpenseLogs')->find($id);

            foreach ($travelExpense->travelExpenseLogs ?? [] as $travelExpenseLog) {
                if ($travelExpenseLog->file_id) {
                    $upload_id = $travelExpenseLog->file_id;
    
                    $travelExpenseLog->update([
                        'file_id' => null
                    ]);
    
                    if (file_exists(asset_path($upload_id))) {
                        unlink(asset_path($upload_id));
                    }
    
                    Upload::destroy($upload_id);
                }
    
                $travelExpenseLog->delete();
            }

            $travelExpense->delete();

            DB::commit();

            return $travelExpense;
        } catch (\Throwable $th) {
            DB::rollBack();
        }
    }

    public function approve($request, $id)
    {
        TravelExpense::where('id', $id)->update([
            'status_id'       => 5,
            'approval_amount' => $request->approval_amount,
            'approved_by'     => auth()->id(),
            'approved_at'     => now(),
        ]);
    }
}
