<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\Attendance;
use App\Models\AttendanceRegularization;
use App\Models\User;
use App\Models\WorkDuration;
use App\Notifications\AttendanceRegularizationRequested;
use App\Notifications\AttendanceRegularizationReviewed;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

class AttendanceRegularizationController extends Controller
{
    public function index(Request $request)
    {
        $user = Auth::user();
        $companyId = $user->company_id;

        $year = $request->filled('year') ? (int) $request->year : (int) date('Y');
        $month = $request->filled('month') ? (int) $request->month : (int) date('n');
        $year = max(2020, min(2030, $year));
        $month = max(1, min(12, $month));

        $startOfMonth = Carbon::createFromDate($year, $month, 1)->startOfDay();
        $endOfMonth = $startOfMonth->copy()->endOfMonth();

        $query = AttendanceRegularization::with(['user', 'reviewer', 'attendance'])
            ->where('company_id', $companyId)
            ->whereBetween('date', [$startOfMonth->toDateString(), $endOfMonth->toDateString()])
            ->orderByDesc('date');

        $directReportIds = $user?->visibleStaffUserIds() ?? [];

        $isManager = count($directReportIds) > 0;
        if ($isManager) {
            $query->where(function ($q) use ($user, $directReportIds) {
                $q->where('user_id', $user->id)->orWhereIn('user_id', $directReportIds);
            });
        } else {
            $query->where('user_id', $user->id);
        }

        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        $regularizations = $query->paginate(15)->withQueryString();

        $canApproveIds = [];
        foreach ($regularizations->items() as $regularization) {
            if ($user?->canApproveRegularization($regularization)) {
                $canApproveIds[] = $regularization->id;
            }
        }

        return view('attendance-regularizations.index', compact('regularizations', 'year', 'month', 'canApproveIds', 'isManager'));
    }

    public function create(Request $request)
    {
        $prefillDate = $request->filled('date')
            ? Carbon::parse($request->date)->toDateString()
            : null;

        return view('attendance-regularizations.create', [
            'prefillDate' => $prefillDate,
        ]);
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'date' => 'required|date|before_or_equal:today',
            'requested_clock_in_time' => 'nullable|date_format:H:i',
            'requested_clock_out_time' => 'nullable|date_format:H:i',
            'reason' => 'required|string|max:1000',
            'redirect_to' => 'nullable|in:attendance',
            'year' => 'nullable|integer',
            'month' => 'nullable|integer|min:1|max:12',
            'employee_id' => 'nullable|integer',
        ]);

        if (
            empty($validated['requested_clock_in_time']) &&
            empty($validated['requested_clock_out_time'])
        ) {
            throw ValidationException::withMessages([
                'requested_clock_in_time' => 'Enter at least a requested clock-in or clock-out time.',
            ]);
        }

        if (
            ! empty($validated['requested_clock_in_time']) &&
            ! empty($validated['requested_clock_out_time']) &&
            $validated['requested_clock_out_time'] < $validated['requested_clock_in_time']
        ) {
            throw ValidationException::withMessages([
                'requested_clock_out_time' => 'Requested clock-out time must be after or equal to clock-in time.',
            ]);
        }

        $user = Auth::user();
        $date = Carbon::parse($validated['date'])->toDateString();

        $pendingExists = AttendanceRegularization::query()
            ->where('company_id', $user->company_id)
            ->where('user_id', $user->id)
            ->whereDate('date', $date)
            ->where('status', AttendanceRegularization::STATUS_PENDING)
            ->exists();
        if ($pendingExists) {
            throw ValidationException::withMessages([
                'date' => 'You already have a pending regularization request for this date.',
            ]);
        }

        $requestedClockIn = ! empty($validated['requested_clock_in_time'])
            ? Carbon::parse($date . ' ' . $validated['requested_clock_in_time'])
            : null;
        $requestedClockOut = ! empty($validated['requested_clock_out_time'])
            ? Carbon::parse($date . ' ' . $validated['requested_clock_out_time'])
            : null;

        $attendance = Attendance::where('company_id', $user->company_id)
            ->where('user_id', $user->id)
            ->where('date', $date)
            ->first();

        $regularization = AttendanceRegularization::create([
            'company_id' => $user->company_id,
            'user_id' => $user->id,
            'attendance_id' => $attendance?->id,
            'date' => $date,
            'requested_clock_in' => $requestedClockIn,
            'requested_clock_out' => $requestedClockOut,
            'reason' => $validated['reason'],
            'status' => AttendanceRegularization::STATUS_PENDING,
        ]);

        $this->notifyRegularizationApprovers($regularization, $user);

        if (($validated['redirect_to'] ?? null) === 'attendance') {
            return redirect()->route('attendance.index', array_filter([
                'year' => $validated['year'] ?? Carbon::parse($date)->year,
                'month' => $validated['month'] ?? Carbon::parse($date)->month,
                'employee_id' => $validated['employee_id'] ?? $user->id,
            ]))->with('success', 'Regularization request submitted. Your manager will be notified.');
        }

        return redirect()->route('attendance-regularizations.index')->with('success', 'Regularization request submitted. Your manager will be notified.');
    }

    public function approve(Request $request, AttendanceRegularization $attendanceRegularization)
    {
        if ($attendanceRegularization->status !== AttendanceRegularization::STATUS_PENDING) {
            return $this->redirectAfterReview($request, 'Request already processed.', 'error');
        }

        $attendanceRegularization->load('user');
        $reviewer = Auth::user();
        if (! $reviewer?->canApproveRegularization($attendanceRegularization)) {
            abort(403, 'You are not allowed to approve this request.');
        }

        $request->validate(['review_remarks' => 'nullable|string|max:500']);
        $attendanceRegularization->update([
            'status' => AttendanceRegularization::STATUS_APPROVED,
            'reviewed_by' => $reviewer->id,
            'reviewed_at' => now(),
            'review_remarks' => $request->review_remarks,
        ]);

        $attendance = null;
        if ($attendanceRegularization->attendance_id && $attendanceRegularization->requested_clock_in) {
            $attendanceRegularization->attendance->update([
                'clock_in_date_time' => $attendanceRegularization->requested_clock_in,
                'clock_out_date_time' => $attendanceRegularization->requested_clock_out ?? $attendanceRegularization->attendance->clock_out_date_time,
            ]);
            $attendance = $attendanceRegularization->attendance->fresh();
        } elseif (! $attendanceRegularization->attendance_id && $attendanceRegularization->requested_clock_in) {
            $attendance = Attendance::create([
                'company_id' => $attendanceRegularization->company_id,
                'user_id' => $attendanceRegularization->user_id,
                'date' => $attendanceRegularization->date,
                'clock_in_date_time' => $attendanceRegularization->requested_clock_in,
                'clock_out_date_time' => $attendanceRegularization->requested_clock_out,
                'status' => 'present',
            ]);
        }

        if ($attendance && $attendanceRegularization->requested_clock_in) {
            $clockIn = $attendanceRegularization->requested_clock_in;
            $clockOut = $attendanceRegularization->requested_clock_out;
            $startTime = $clockIn->format('H:i:s');
            $endTime = $clockOut?->format('H:i:s');

            $session = WorkDuration::query()
                ->where('company_id', $attendance->company_id)
                ->where('attendance_id', $attendance->id)
                ->where('start_time', $startTime)
                ->where('end_time', $endTime)
                ->first();

            if (! $session) {
                WorkDuration::create([
                    'company_id' => $attendance->company_id,
                    'attendance_id' => $attendance->id,
                    'start_time' => $startTime,
                    'end_time' => $endTime,
                    'duration' => $clockOut ? $clockIn->diffInSeconds($clockOut) : null,
                    'status' => $clockOut ? 'closed' : 'open',
                    'notes' => 'Regularization approved',
                ]);
            }

            $attendance->update([
                'clock_in_time' => $clockIn->format('H:i:s'),
                'clock_out_time' => $clockOut?->format('H:i:s'),
                'total_duration' => (int) WorkDuration::query()
                    ->where('company_id', $attendance->company_id)
                    ->where('attendance_id', $attendance->id)
                    ->sum('duration'),
            ]);
        }

        $attendanceRegularization->user?->notify(new AttendanceRegularizationReviewed($attendanceRegularization, 'approved'));

        return $this->redirectAfterReview($request, 'Request approved.', 'success');
    }

    public function reject(Request $request, AttendanceRegularization $attendanceRegularization)
    {
        if ($attendanceRegularization->status !== AttendanceRegularization::STATUS_PENDING) {
            return $this->redirectAfterReview($request, 'Request already processed.', 'error');
        }

        $attendanceRegularization->load('user');
        $reviewer = Auth::user();
        if (! $reviewer?->canApproveRegularization($attendanceRegularization)) {
            abort(403, 'You are not allowed to reject this request.');
        }

        $request->validate(['review_remarks' => 'nullable|string|max:500']);
        $attendanceRegularization->update([
            'status' => AttendanceRegularization::STATUS_REJECTED,
            'reviewed_by' => $reviewer->id,
            'reviewed_at' => now(),
            'review_remarks' => $request->review_remarks,
        ]);

        $attendanceRegularization->user?->notify(new AttendanceRegularizationReviewed($attendanceRegularization, 'rejected'));

        return $this->redirectAfterReview($request, 'Request rejected.', 'success');
    }

    protected function notifyRegularizationApprovers(AttendanceRegularization $regularization, User $requester): void
    {
        $notified = [];
        $cursorId = $requester->report_to;

        while ($cursorId) {
            if (in_array((int) $cursorId, $notified, true)) {
                break;
            }
            $manager = User::withoutGlobalScopes()->find($cursorId);
            if (! $manager) {
                break;
            }
            $manager->notify(new AttendanceRegularizationRequested($regularization));
            $notified[] = (int) $manager->id;
            $cursorId = $manager->report_to;
        }
    }

    protected function redirectAfterReview(Request $request, string $message, string $type): RedirectResponse
    {
        if ($request->input('redirect_to') === 'attendance') {
            return redirect()->route('attendance.index', array_filter([
                'year' => $request->integer('year') ?: null,
                'month' => $request->integer('month') ?: null,
                'employee_id' => $request->integer('employee_id') ?: null,
            ]))->with($type, $message);
        }

        return redirect()->route('attendance-regularizations.index')->with($type, $message);
    }
}
