<?php

namespace App\Services;

use App\Models\Employee;
use App\Models\Punch;
use App\Models\Attendance;
use Carbon\Carbon;

class AttendanceProcessor
{
    /**
     * Process attendance for a specific date.
     *
     * @param string     $dateString  The date to process (Y-m-d)
     * @param int|null   $employeeUserId  The users.id of the employee (employee's user_id). 
     */
    public function processForDate($dateString, $employeeUserId = null)
    {
        $date = Carbon::parse($dateString)->startOfDay();

        $query = Employee::with('shift');
        if ($employeeUserId) {
            $query->where('user_id', $employeeUserId);
        }
        $employees = $query->get();

        foreach ($employees as $employee) {
            $shift       = $employee->shift;
            $isNightShift = $shift && strtolower($shift->is_night_shift) === 'yes';

            if ($isNightShift) {
                $searchStart = $date->copy()->setHour(12)->setMinute(0)->setSecond(0);
                $searchEnd   = $date->copy()->addDay()->setHour(12)->setMinute(0)->setSecond(0);
            } else {
                $searchStart = $date->copy()->startOfDay();
                $searchEnd   = $date->copy()->endOfDay();
            }

            // Clear previously calculated working_minutes and break_minutes for this day
            Punch::where('employee_id', $employee->user_id)
                ->whereBetween('punch_time', [$searchStart, $searchEnd])
                ->update(['working_minutes' => 0, 'break_minutes' => 0]);

            $punches = Punch::where('employee_id', $employee->user_id)
                ->whereBetween('punch_time', [$searchStart, $searchEnd])
                ->orderBy('punch_time', 'asc')
                ->get();

            if ($punches->isEmpty()) {
                Attendance::updateOrCreate(
                    [
                        'employee_id'     => $employee->user_id,
                        'attendance_date' => $date->format('Y-m-d'),
                    ],
                    [
                        'company_id'           => $employee->company_id,
                        'shift_id'             => $shift?->id,
                        'first_in'             => null,
                        'last_out'             => null,
                        'total_working_hours'  => 0,
                        'total_break_minutes'  => 0,
                        'gross_minutes'        => 0,
                        'status'               => 'Absent',
                    ]
                );
                continue;
            }

            $firstIn  = $punches->first()->punch_time;
            $lastOut  = $punches->count() > 1 ? $punches->last()->punch_time : null;

            $totalMinutes = 0;
            $totalBreakMinutes = 0;
            $lastInTime   = null;
            $previousOutPunch = null;

            foreach ($punches as $punch) {
                if ($punch->status === 'In' || $punch->status === 'Unknown') {
                    if (!$lastInTime) {
                        $lastInTime = $punch->punch_time;
                        
                        // Calculate break before this IN
                        if ($previousOutPunch) {
                            $breakBefore = $previousOutPunch->punch_time->diffInMinutes($lastInTime);
                            $totalBreakMinutes += $breakBefore;
                            // Save break duration in the PREVIOUS OUT punch
                            $previousOutPunch->update(['break_minutes' => $breakBefore]);
                        }

                        if ($punch->status === 'Unknown') {
                            // Leave it open, the next Unknown will act as Out
                        }
                    } elseif ($punch->status === 'Unknown') {
                        // Treat as OUT
                        $diff = $lastInTime->diffInMinutes($punch->punch_time);
                        $totalMinutes += $diff;

                        // Save working duration in this OUT punch
                        $punch->update(['working_minutes' => $diff]);
                        
                        $previousOutPunch = $punch;
                        $lastInTime = null;
                    }
                } elseif ($punch->status === 'Out') {
                    if ($lastInTime) {
                        $diff = $lastInTime->diffInMinutes($punch->punch_time);
                        $totalMinutes += $diff;

                        // Save working duration in this OUT punch
                        $punch->update(['working_minutes' => $diff]);
                        
                        $previousOutPunch = $punch;
                        $lastInTime = null;
                    }
                }
            }

            if ($totalMinutes == 0 && $firstIn && $lastOut) {
                $totalMinutes = $firstIn->diffInMinutes($lastOut);
                // Also update the single last punch if we fell back to this
                $lastPunchObj = $punches->last();
                if ($lastPunchObj) {
                    $lastPunchObj->update(['working_minutes' => $totalMinutes]);
                }
            }

            $totalWorkingHours = round($totalMinutes / 60, 2);
            $grossMinutes = 0;
            if ($firstIn && $lastOut) {
                $grossMinutes = $firstIn->diffInMinutes($lastOut);
            }

            Attendance::updateOrCreate(
                [
                    'employee_id'     => $employee->user_id,
                    'attendance_date' => $date->format('Y-m-d'),
                ],
                [
                    'company_id'          => $employee->company_id,
                    'shift_id'            => $shift?->id,
                    'first_in'            => $firstIn,
                    'last_out'            => $lastOut,
                    'total_working_hours' => $totalWorkingHours,
                    'total_break_minutes' => $totalBreakMinutes,
                    'gross_minutes'       => $grossMinutes,
                    'status'              => 'Present',
                ]
            );
        }
    }
}
