<?php

namespace App\Http\Controllers\Backend\Report;

use Carbon\Carbon;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Models\Track\LocationLog;
use App\Http\Controllers\Controller;
use App\Repositories\UserRepository;
use Brian2694\Toastr\Facades\Toastr;
use Maatwebsite\Excel\Facades\Excel;
use App\Models\Hrm\Attendance\Holiday;
use App\Models\Hrm\Attendance\Weekend;
use App\Models\Hrm\Leave\LeaveRequest;
use App\Models\Hrm\Attendance\Attendance;
use App\Repositories\Admin\RoleRepository;
use App\Helpers\CoreApp\Traits\DateHandler;
use App\Services\Export\ExportExcelService;
use App\Models\coreApp\Relationship\RelationshipTrait;
use App\Repositories\Report\AttendanceReportRepository;
use App\Repositories\Hrm\Attendance\AttendanceRepository;
use App\Repositories\Hrm\Department\DepartmentRepository;

class AttendanceReportController extends Controller
{
    use RelationshipTrait, DateHandler;

    protected $attendanceReport;
    protected $department;
    protected $roleRepository;
    protected $attendance_repo;
    protected $userRepository;
    protected $users;

    public function __construct(
        AttendanceReportRepository $attendanceReportRepository,
        DepartmentRepository $department,
        UserRepository $users,
        AttendanceRepository $attendance_repo,
        RoleRepository $roleRepository
    ) {
        $this->attendanceReport = $attendanceReportRepository;
        $this->department = $department;
        $this->users = $users;
        $this->attendance_repo = $attendance_repo;
        $this->roleRepository = $roleRepository;
    }

    public function index(Request $request)
    {
        try {
            if ($request->ajax()) {
                return $this->attendanceReport->table($request);
            }
            $data['class']  = 'report_attendance_table';
            $data['fields'] = $this->attendance_repo->report_fields();
            $data['checkbox'] = true;
            $data['table']     = route('attendance.index');
            $data['url_id']    = 'report_attendance_table_url';
            $data['title'] = _trans('attendance.Attendance History');
            $data['departments'] = $this->department->getAll();
            $data['users'] = $this->users->getAll();
            return view('backend.report.attendance.index', compact('data'));
        } catch (\Throwable $th) {
            Toastr::error(_trans('response.Something went wrong.'), 'Error');
            return redirect()->back();
        }
    }

    public function liveTracking(Request $request)
    {
        $data['title'] = _trans('attendance.Live Tracking');
        $data['roles'] = $this->roleRepository->getAll();
        $data['date'] = $request->date ? $request->date : date('Y-m-d');
        return view('backend.report.live_tracking.index', compact('data'));
    }

    public function liveTrackingEmployee(Request $request)
    {
        return $this->users->liveTrackingEmployee($request);
    }

    public function locationHistory(Request $request)
    {
        $data['title'] = _trans('attendance.Location History');
        $data['users'] = $this->users->getAll();
        $data['date'] = $request->date ? $request->date : date('Y-m-d');
        $data['user'] = $request->user ? $request->user : null;
        return view('backend.report.live_tracking.location_history', compact('data'));
    }
    public function locationTimeline(Request $request)
    {

        $data['title'] = _trans('attendance.Location Timeline');
        $data['timeline'] = LocationLog::where('user_id', $request->user)->where('date', $request->date)->get();
        $data['users'] = $this->users->getAll();
        $data['date'] = $request->date ? $request->date : date('Y-m-d');
        $data['user'] = $request->user ? $request->user : null;
        $data['input'] = $request->all();
        return view('backend.report.live_tracking.location_timeline', compact('data'));
    }

    public function employeeLocationHistory(Request $request)
    {
        return $this->users->employeeLocationHistory($request);
    }

    public function employeeAttendanceHistory(User $user)
    {
        $data['title'] = _trans('attendance.Show attendance');
        $data['show'] = $user;
        $data['monthArray'] = $this->getCurrentMonthDays();
        return view('backend.attendance.attendance.show', compact('data'));
    }

    public function reportDataTable(Request $request)
    {
        return $this->attendanceReport->attendanceDatatable($request);
    }

    public function singleReportDataTable(Request $request, User $user)
    {
        if ($request->month) {
            $monthArray = $this->getSelectedMonthDays($request->month);
        } else {
            $monthArray = $this->getCurrentMonthDays();
        }
        return $this->attendanceReport->singleAttendanceDatatable($user, $request, $monthArray);
    }

    public function singleAttendanceSummaryReport(Request $request, User $user)
    {
        $monthlySummary = $this->attendanceReport->singleAttendanceSummary($user, $request);
        return view('backend.attendance.attendance.summary.summary', compact('monthlySummary'));
    }


    public function checkInDetails(Request $request)
    {
        $data['title'] = _trans('attendance.Attendance Details');
        $data['attendance'] = $this->attendanceReport->attendanceDetails($request);
        return view('backend.modal.attendance_details', compact('data'));
    }

    public function checkInOutApprovalOnTime($id, $type)
    {
        $this->attendanceReport->attendanceOnTimeApproval($id, $type);
        if ($type === 'checkin') {
            Toastr::success(_trans('response.Check In Approved Successfully'), 'Success');
        } else {
            Toastr::success(_trans('response.Check Out Approved Successfully'), 'Success');
        }
        return redirect()->back();
    }

    public function attendanceReportEmployeeWise(Request $request)
    {
        try {
            $request->merge(['month' => request('month') ? request('month') : date('Y-m')]);

            $data['year'] = Carbon::parse(request('month') ? request('month') : date('Y-m'))->format('Y');
            $data['month'] = Carbon::parse(request('month') ? request('month') : date('Y-m'))->format('m');
            $data['totalDays'] = cal_days_in_month(CAL_GREGORIAN, $data['month'], $data['year']);

            $users = User::where(currentCompanyCurrentBranch());

            if (!isAdminOrHr()) {
                $users = $users->whereIn('id', getRelatedUserIds());
            }

            $data['title'] = _trans('common.Attendance Report') . ' ' . date('M Y', strtotime(request('month')));

            $data['users'] = $users->get(['id', 'name', 'employee_id']);

            $reports = User::query()
                ->where(currentCompanyCurrentBranch())
                ->with(['designation:id,title', 'department:id,title'])
                ->select('id', 'name', 'employee_id', 'department_id', 'designation_id', 'joining_date', 'company_id', 'branch_id');

            if (!isAdminOrHr()) {
                $reports = $reports->whereIn('id', getRelatedUserIds());
            }

            $reports = $reports
                ->when(request('user_id'), fn($q) => $q->where('id', request('user_id')))
                ->when(request('department_id'), fn($q) => $q->where('department_id', request('department_id')));

            if ($request->filled('excel_export') && $request->excel_export) {
                $excelData['company_logo'] = public_path('assets/images/logo/dark.png');
                $excelData['data'] = $data;
                $excelData['generated_by'] = auth()->user() ? auth()->user()->name : '';
                $excelData['view'] = 'backend.report.attendance.export-employee-wise-report';
                $excelData['totalDays'] = $data['totalDays'];
                $excelData['title'] = _trans('common.Attendance Report') . ' ' . date('M Y', strtotime(request('month')));
                $excelData['reports']   = $reports->get()
                    ->map(function ($user) use ($data) {
                        return [
                            "employee_name" => $user->name,
                            "employee_id" => $user->employee_id,
                            "department" => @$user->department->title,
                            "designation" => @$user->designation->title,
                            "month_statuses" => $this->monthStatuses($user, $data['totalDays'])
                        ];
                    });

                $fileName = $data['title'] . '-' . time() . '.xlsx';
                return Excel::download(new ExportExcelService($excelData), $fileName);
            } else {
                $data['reports'] = $reports->paginate(15)
                    ->through(function ($user) use ($data) {
                        return [
                            "employee_name" => $user->name,
                            "employee_id" => $user->employee_id,
                            "department" => @$user->department->title,
                            "designation" => @$user->designation->title,
                            "month_statuses" => $this->monthStatuses($user, $data['totalDays'])
                        ];
                    });
            }

            return view('backend.report.attendance.employee-wise-report', compact('data'));
        } catch (\Exception $exception) {
            Toastr::error(_trans('response.Something went wrong!'), 'Error');

            return redirect()->back();
        }
    }

    protected function monthStatuses($employee, $totalDays)
    {
        $data = [
            'statuses' => [],
            'totalPresent' => 0,
            'totalAbsent' => 0,
            'totalWeekend' => 0,
            'totalHoliday' => 0,
            'totalLeave' => 0,
            'totalNotJoin' => 0,
            'totalNotAvailable' => 0,
        ];

        $companyId = auth()->user()->company_id;
        $month = request('month');
        $weekends = Weekend::where('company_id', $companyId)
            ->where('is_weekend', 'yes')
            ->pluck('name')
            ->map(fn($name) => Str::lower($name))
            ->toArray();

        $today = Carbon::now()->format('Y-m-d');

        for ($day = 1; $day <= $totalDays; $day++) {
            $date = Carbon::parse("$month-$day")->format('Y-m-d');

            if ($date > $today) {
                $data['statuses'][] = '<span class="text-secondary fw-bold">' . _trans('common.-') . '</span>';
                $data['totalNotAvailable']++;
            } elseif ($employee->joining_date > $date) {
                $data['statuses'][] = '<span class="text-info fw-bold">' . _trans('common.NJ') . '</span>';
                $data['totalNotJoin']++;
            } elseif ($this->isPresent($employee->id, $date)) {
                $data['statuses'][] = '<span class="text-success fw-bold">' . _trans('common.P') . '</span>';
                $data['totalPresent']++;
            } elseif ($this->isOnLeave($employee->id, $date)) {
                $data['statuses'][] = '<span class="text-info fw-bold">' . _trans('common.L') . '</span>';
                $data['totalLeave']++;
            } elseif ($this->isHoliday($companyId, $date)) {
                $data['statuses'][] = '<span class="text-danger fw-bold">' . _trans('common.H') . '</span>';
                $data['totalHoliday']++;
            } elseif ($this->isWeekend($date, $weekends)) {
                $data['statuses'][] = '<span class="text-warning fw-bold">' . _trans('common.W') . '</span>';
                $data['totalWeekend']++;
            } else {
                $data['statuses'][] = '<span class="text-danger fw-bold">' . _trans('common.A') . '</span>';
                $data['totalAbsent']++;
            }
        }

        return $data;
    }

    private function isPresent($userId, $date)
    {
        return Attendance::where(['user_id' => $userId, 'date' => $date])->exists();
    }

    private function isOnLeave($userId, $date)
    {
        return LeaveRequest::where('user_id', $userId)
            ->where(function ($query) use ($date) {
                $query->where('leave_from', '<=', $date)
                    ->where('leave_to', '>=', $date);
            })
            ->whereIn('status_id', [1, 5])
            ->exists();
    }

    private function isHoliday($companyId, $date)
    {
        return Holiday::where('company_id', $companyId)
            ->where(function ($query) use ($date) {
                $query->where('start_date', '<=', $date)
                    ->where('end_date', '>=', $date);
            })
            ->exists();
    }

    private function isWeekend($date, $weekends)
    {
        $dayName = Carbon::parse($date)->translatedFormat('l');
        return in_array(Str::lower($dayName), $weekends);
    }
}
