<?php

namespace App\Http\Controllers;

use App\Models\Attendance;
use App\Models\Employee;
use App\Models\LeaveRequest;
use Illuminate\Http\Request;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Yajra\DataTables\DataTables;

class AttendanceReportController extends Controller
{
    private function getAccessibleEmployeeIds()
    {
        $user = Auth::user();
        if ($user->hasRole('Admin')) {
            return Employee::pluck('id')->toArray();
        }

        $employeeId = $user->employee_id;
        if (!$employeeId) return [];

        $subordinateIds = Employee::where('manager_id', $employeeId)->pluck('id')->toArray();
        return array_merge([$employeeId], $subordinateIds);
    }

    public function daily(Request $request)
    {
        $date = $request->get('date', Carbon::today()->toDateString());
        $employeeIds = $this->getAccessibleEmployeeIds();
        $employees = Employee::whereIn('id', $employeeIds)->get();

        if ($request->ajax()) {
            $presentCount = 0;
            $absentCount = 0;
            $leaveCount = 0;

            $data = $employees->map(function ($employee) use ($date, &$presentCount, &$absentCount, &$leaveCount) {
                $attendance = Attendance::where('employee_id', $employee->id)
                    ->where('date', $date)
                    ->first();
                
                $leave = LeaveRequest::where('employee_id', $employee->id)
                    ->where('status', 'Approved')
                    ->where('start_date', '<=', $date)
                    ->where('end_date', '>=', $date)
                    ->first();

                $status = 'Absent';
                if ($attendance) {
                    $status = 'Present';
                    $presentCount++;
                } elseif ($leave) {
                    $status = 'On Leave (' . $leave->leave_type . ')';
                    $leaveCount++;
                } else {
                    $absentCount++;
                }

                return [
                    'name' => $employee->name,
                    'designation' => $employee->designation,
                    'status' => $status,
                    'punch_in' => $attendance ? Carbon::parse($attendance->punch_in)->format('H:i') : '-',
                    'punch_out' => $attendance && $attendance->punch_out ? Carbon::parse($attendance->punch_out)->format('H:i') : ($attendance ? 'Still In' : '-'),
                    'duration' => $attendance ? $attendance->working_hours : '-',
                ];
            });

            $aggregates = [
                'total' => count($employees),
                'present' => $presentCount,
                'absent' => $absentCount,
                'leave' => $leaveCount
            ];

            return DataTables::of($data)
                ->with('aggregates', $aggregates)
                ->make(true);
        }

        return view('attendance.reports.daily', compact('date'));
    }

    public function monthly(Request $request)
    {
        $month = $request->get('month', Carbon::now()->format('m'));
        $year = $request->get('year', Carbon::now()->format('Y'));
        $employeeId = $request->get('employee_id');
        
        $employeeIds = $this->getAccessibleEmployeeIds();
        $query = Employee::whereIn('id', $employeeIds);
        
        if ($employeeId) {
            $query->where('id', $employeeId);
        }
        
        $employees = $query->get();
        $daysInMonth = Carbon::createFromDate($year, $month, 1)->daysInMonth;
        
        if ($request->ajax()) {
            $orgTotalP = 0;
            $orgTotalDays = 0;
            $topPerformers = 0;
            $frequentAbsentees = 0;

            $data = $employees->map(function ($employee) use ($month, $year, $daysInMonth, &$orgTotalP, &$orgTotalDays, &$topPerformers, &$frequentAbsentees) {
                $row = [
                    'id' => $employee->id,
                    'name' => $employee->name,
                    'designation' => $employee->designation,
                ];

                $pCount = 0;
                $aCount = 0;
                $lCount = 0;

                for ($day = 1; $day <= $daysInMonth; $day++) {
                    $date = sprintf('%04d-%02d-%02d', $year, $month, $day);
                    
                    $attendance = Attendance::where('employee_id', $employee->id)
                        ->where('date', $date)
                        ->first();
                    
                    if ($attendance) {
                        $row['day_' . $day] = 'P';
                        $pCount++;
                        $orgTotalP++;
                    } else {
                        $leave = LeaveRequest::where('employee_id', $employee->id)
                            ->where('status', 'Approved')
                            ->where('start_date', '<=', $date)
                            ->where('end_date', '>=', $date)
                            ->first();
                        
                        if ($leave) {
                            $row['day_' . $day] = 'L';
                            $lCount++;
                        } else {
                            $row['day_' . $day] = 'A';
                            $aCount++;
                        }
                    }
                    $orgTotalDays++;
                }

                $row['total_p'] = $pCount;
                $row['total_a'] = $aCount;
                $row['total_l'] = $lCount;

                // Thresholds for org stats
                if ($pCount == $daysInMonth) $topPerformers++;
                if ($aCount > 5) $frequentAbsentees++;

                return $row;
            });

            $avgPresence = $orgTotalDays > 0 ? round(($orgTotalP / $orgTotalDays) * 100, 1) : 0;

            $aggregates = [
                'avg_presence' => $avgPresence,
                'top_performers' => $topPerformers,
                'frequent_absentees' => $frequentAbsentees
            ];

            return DataTables::of($data)
                ->with('aggregates', $aggregates)
                ->make(true);
        }

        return view('attendance.reports.monthly', compact('month', 'year', 'daysInMonth'));
    }

    public function yearly(Request $request)
    {
        $year = $request->get('year', Carbon::now()->format('Y'));
        $employeeId = $request->get('employee_id');
        
        $employeeIds = $this->getAccessibleEmployeeIds();
        $query = Employee::whereIn('id', $employeeIds);
        
        if ($employeeId) {
            $query->where('id', $employeeId);
        }
        
        $employees = $query->get();

        if ($request->ajax()) {
            $data = $employees->map(function ($employee) use ($year) {
                $summary = [
                    'id' => $employee->id,
                    'name' => $employee->name,
                    'designation' => $employee->designation,
                ];

                for ($m = 1; $m <= 12; $m++) {
                    $monthName = Carbon::createFromDate($year, $m, 1)->format('M');
                    $present = Attendance::where('employee_id', $employee->id)
                        ->whereYear('date', $year)
                        ->whereMonth('date', $m)
                        ->count();
                    $summary[$monthName] = $present;
                }
                
                $summary['total'] = Attendance::where('employee_id', $employee->id)
                        ->whereYear('date', $year)
                        ->count();

                return $summary;
            });

            return DataTables::of($data)->make(true);
        }

        return view('attendance.reports.yearly', compact('year'));
    }

    public function issues()
    {
        return view('attendance.reports.issues');
    }

    public function getIssuesData(Request $request)
    {
        $settings = \App\Models\BusinessSetting::first();
        $standardPunchIn = $settings->standard_punch_in_time ?? '09:00:00';
        $minimumHours = (float) ($settings->minimum_working_hours ?? 8);

        // Get date range
        $startDate = $request->start_date ?? Carbon::now()->startOfMonth()->toDateString();
        $endDate = $request->end_date ?? Carbon::now()->endOfMonth()->toDateString();

        // Build query
        $query = Attendance::with('employee')
            ->whereBetween('date', [$startDate, $endDate]);

        // Filter by employee if specified
        $accessibleIds = $this->getAccessibleEmployeeIds();
        if ($request->employee_id) {
            // Ensure the requested ID is within permitted scope
            if (in_array($request->employee_id, $accessibleIds)) {
                $query->where('employee_id', $request->employee_id);
            } else {
                // If unauthorized ID requested, return nothing
                $query->where('employee_id', 0);
            }
        } else {
            // General filter: restrict to accessible employees
            $query->whereIn('employee_id', $accessibleIds);
        }

        // Filter by issue type
        $issueType = $request->issue_type;

        return DataTables::of($query)
            ->filter(function ($query) use ($issueType, $standardPunchIn, $minimumHours) {
                if ($issueType === 'late') {
                    // Only late punches
                    $query->whereNotNull('punch_in')
                        ->whereRaw("TIME(punch_in) > ?", [$standardPunchIn]);
                } elseif ($issueType === 'low_hours') {
                    // Only low attendance (need to calculate)
                    $query->whereNotNull('punch_in')->whereNotNull('punch_out');
                } elseif ($issueType === 'incomplete') {
                    // Only incomplete records
                    $query->whereNotNull('punch_in')->whereNull('punch_out');
                }
            })
            ->addColumn('employee_name', function ($attendance) {
                return $attendance->employee->name ?? 'N/A';
            })
            ->addColumn('employee_id_display', function ($attendance) {
                return $attendance->employee->employee_id ?? 'N/A';
            })
            ->editColumn('date', function ($attendance) {
                return Carbon::parse($attendance->date)->format('d M Y');
            })
            ->addColumn('punch_in_time', function ($attendance) {
                return $attendance->punch_in ? Carbon::parse($attendance->punch_in)->format('h:i A') : '-';
            })
            ->addColumn('punch_out_time', function ($attendance) {
                return $attendance->punch_out ? Carbon::parse($attendance->punch_out)->format('h:i A') : '-';
            })
            ->addColumn('worked_hours', function ($attendance) {
                if ($attendance->punch_in && $attendance->punch_out) {
                    $hours = Carbon::parse($attendance->punch_in)->diffInHours(Carbon::parse($attendance->punch_out), true);
                    return number_format($hours, 2) . ' hrs';
                }
                return '-';
            })
            ->addColumn('issues', function ($attendance) use ($standardPunchIn, $minimumHours) {
                $badges = [];
                
                if ($attendance->punch_in) {
                    // Check late
                    $standardTime = Carbon::parse($attendance->date . ' ' . $standardPunchIn);
                    $actualPunchIn = Carbon::parse($attendance->punch_in);
                    
                    if ($actualPunchIn->gt($standardTime)) {
                        $minutes = $actualPunchIn->diffInMinutes($standardTime);
                        $badges[] = '<span class="badge bg-light-warning text-warning border border-warning px-2">Late (' . $minutes . ' min)</span>';
                    }
                    
                    // Check low hours
                    if ($attendance->punch_out) {
                        $workedHours = $actualPunchIn->diffInHours(Carbon::parse($attendance->punch_out), true);
                        if ($workedHours < $minimumHours) {
                            $shortfall = round($minimumHours - $workedHours, 2);
                            $badges[] = '<span class="badge bg-light-danger text-danger border border-danger px-2">Low Hours (-' . $shortfall . ' hrs)</span>';
                        }
                    } else {
                        $badges[] = '<span class="badge bg-light-secondary text-secondary border border-secondary px-2">Incomplete</span>';
                    }
                }
                
                return implode(' ', $badges);
            })
            ->rawColumns(['issues'])
            ->make(true);
    }

    public function exportIssues(Request $request)
    {
        $settings = \App\Models\BusinessSetting::first();
        $standardPunchIn = $settings->standard_punch_in_time ?? '09:00:00';
        $minimumHours = (float) ($settings->minimum_working_hours ?? 8);

        $startDate = $request->start_date ?? Carbon::now()->startOfMonth()->toDateString();
        $endDate = $request->end_date ?? Carbon::now()->endOfMonth()->toDateString();

        $query = Attendance::with('employee')
            ->whereBetween('date', [$startDate, $endDate]);

        $accessibleIds = $this->getAccessibleEmployeeIds();
        if ($request->employee_id) {
            // Ensure the requested ID is within permitted scope
            if (in_array($request->employee_id, $accessibleIds)) {
                $query->where('employee_id', $request->employee_id);
            } else {
                // If unauthorized ID requested, fallback to all accessible
                $query->whereIn('employee_id', $accessibleIds);
            }
        } else {
            $query->whereIn('employee_id', $accessibleIds);
        }

        $attendances = $query->get();

        $filename = 'attendance_issues_' . date('Y-m-d_His') . '.csv';
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ];

        $callback = function() use ($attendances, $standardPunchIn, $minimumHours) {
            $file = fopen('php://output', 'w');
            
            fputcsv($file, [
                'Employee ID',
                'Employee Name',
                'Date',
                'Punch In',
                'Punch Out',
                'Worked Hours',
                'Issues'
            ]);

            foreach ($attendances as $attendance) {
                $issues = [];
                
                if ($attendance->punch_in) {
                    $standardTime = Carbon::parse($attendance->date . ' ' . $standardPunchIn);
                    $actualPunchIn = Carbon::parse($attendance->punch_in);
                    
                    if ($actualPunchIn->gt($standardTime)) {
                        $minutes = $actualPunchIn->diffInMinutes($standardTime);
                        $issues[] = 'Late (' . $minutes . ' min)';
                    }
                    
                    if ($attendance->punch_out) {
                        $workedHours = $actualPunchIn->diffInHours(Carbon::parse($attendance->punch_out), true);
                        if ($workedHours < $minimumHours) {
                            $shortfall = round($minimumHours - $workedHours, 2);
                            $issues[] = 'Low Hours (-' . $shortfall . ' hrs)';
                        }
                        $hoursDisplay = number_format($workedHours, 2);
                    } else {
                        $issues[] = 'Incomplete';
                        $hoursDisplay = '-';
                    }
                } else {
                    $hoursDisplay = '-';
                }

                fputcsv($file, [
                    $attendance->employee->employee_id ?? '',
                    $attendance->employee->name ?? '',
                    Carbon::parse($attendance->date)->format('Y-m-d'),
                    $attendance->punch_in ? Carbon::parse($attendance->punch_in)->format('H:i') : '-',
                    $attendance->punch_out ? Carbon::parse($attendance->punch_out)->format('H:i') : '-',
                    $hoursDisplay,
                    implode(', ', $issues)
                ]);
            }

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }
}
