<?php

namespace App\Http\Controllers;

use App\Enums\UserType;
use App\Models\Department;
use App\Models\LeaveRequest;
use App\Models\User;
use App\Http\Requests\StoreAttendanceRequest;
use App\Services\AttendanceService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Inertia\Inertia;

class AttendanceController extends Controller
{
    public function __construct(protected AttendanceService $attendanceService) {}

    public function index(Request $request)
    {
        $user = auth()->user() ?? $request->user();

        if (! $user) {
            return redirect()->route('login');
        }

        $isAdmin = in_array($user->type->value, ['admin', 'super-admin']);

        if ($isAdmin) {
            $selectedDate = $request->filled('date')
                ? Carbon::parse($request->string('date'))->toDateString()
                : Carbon::today()->toDateString();
            $departmentId = $request->integer('department_id') ?: null;

            $employees = User::query()
                ->where('type', UserType::EMPLOYEE)
                ->with([
                    'employeeProfile.departmentRel:id,name',
                    'attendances' => function ($query) use ($selectedDate) {
                        $query->whereDate('date', $selectedDate);
                    },
                ])
                ->when($departmentId, function ($query) use ($departmentId) {
                    $query->whereHas('employeeProfile', function ($profileQuery) use ($departmentId) {
                        $profileQuery->where('department_id', $departmentId);
                    });
                })
                ->orderBy('name')
                ->get();

            $leaveUserIds = LeaveRequest::query()
                ->whereIn('user_id', $employees->pluck('id'))
                ->where('status', 'approved')
                ->whereDate('start_date', '<=', $selectedDate)
                ->whereDate('end_date', '>=', $selectedDate)
                ->pluck('user_id')
                ->flip();

            $employees = $employees
                ->map(function (User $employee) use ($leaveUserIds, $selectedDate) {
                    $attendance = $employee->attendances->first();
                    $finalStatus = $this->attendanceService->resolveDailyStatus(
                        $attendance,
                        $leaveUserIds->has($employee->id),
                        $selectedDate
                    );

                    return [
                        'id' => $employee->id,
                        'name' => $employee->name,
                        'email' => $employee->email,
                        'department' => $employee->employeeProfile?->departmentRel?->name,
                        'status' => $finalStatus,
                        'attendance' => $attendance ? [
                            'id' => $attendance->id,
                            'date' => $attendance->date?->toDateString() ?? $attendance->date,
                            'clock_in' => $attendance->clock_in,
                            'clock_out' => $attendance->clock_out,
                            'total_hours' => $attendance->total_hours,
                            'status' => $attendance->status,
                            'in_type' => $attendance->in_type,
                            'out_type' => $attendance->out_type,
                        ] : null,
                    ];
                })
                ->values();

            $stats = [
                'employees' => $employees->count(),
                'present' => $employees->where('status', 'present')->count(),
                'late' => $employees->where('status', 'late')->count(),
                'leave' => $employees->where('status', 'leave')->count(),
                'absent' => $employees->where('status', 'absent')->count(),
            ];

            return Inertia::render('Admin/Attendance/Index', [
                'employees' => $employees,
                'departments' => Department::query()->select(['id', 'name'])->orderBy('name')->get(),
                'stats' => $stats,
                'filters' => [
                    'date' => $selectedDate,
                    'department_id' => $departmentId,
                ],
            ]);
        }

        $currentMonth = Carbon::now()->startOfMonth();
        $selectedMonth = $currentMonth->copy();
        $requestedMonth = $request->query('month');

        if (is_string($requestedMonth) && preg_match('/^\d{4}-\d{2}$/', $requestedMonth) === 1) {
            try {
                $parsedMonth = Carbon::createFromFormat('Y-m', $requestedMonth)->startOfMonth();
                $selectedMonth = $parsedMonth->gt($currentMonth) ? $currentMonth->copy() : $parsedMonth;
            } catch (\Throwable $exception) {
                $selectedMonth = $currentMonth->copy();
            }
        }

        $monthStart = $selectedMonth->copy()->startOfMonth();
        $monthEnd = $selectedMonth->copy()->endOfMonth();

        return Inertia::render('Employee/Pages/Attendance/Index', [
            'today' => $this->attendanceService->getTodayStatus($user),
            'timesheet' => $this->attendanceService->getAttendanceRecords($user, $monthStart, $monthEnd),
            'filters' => [
                'month' => $selectedMonth->format('Y-m'),
            ],
            'employees' => collect(),
            'selectedUser' => null,
        ]);
    }

    public function employeeDetails(Request $request, User $employee)
    {
        $user = auth()->user() ?? $request->user();

        if (! $user || ! in_array($user->type->value, ['admin', 'super-admin'])) {
            abort(403, 'Unauthorized action.');
        }

        if ($employee->type !== UserType::EMPLOYEE) {
            abort(404);
        }

        $startDate = $request->filled('start_date')
            ? Carbon::parse($request->string('start_date'))->startOfDay()
            : Carbon::now()->startOfMonth()->startOfDay();
        $endDate = $request->filled('end_date')
            ? Carbon::parse($request->string('end_date'))->endOfDay()
            : Carbon::now()->endOfMonth()->endOfDay();

        if ($startDate->gt($endDate)) {
            [$startDate, $endDate] = [$endDate->copy()->startOfDay(), $startDate->copy()->endOfDay()];
        }

        $records = $this->attendanceService->getAttendanceRecords($employee, $startDate, $endDate);
        $workedRecords = $records->filter(fn ($record) => ! is_null($record->clock_in));
        $totalHours = $workedRecords->sum(fn ($record) => (float) ($record->total_hours ?? 0));

        return Inertia::render('Admin/Attendance/EmployeeDetail', [
            'employee' => $employee->only(['id', 'name', 'email']),
            'department' => $employee->employeeProfile?->departmentRel?->name,
            'records' => $records,
            'summary' => [
                'days_worked' => $workedRecords->count(),
                'total_hours' => round($totalHours, 2),
                'avg_daily' => $workedRecords->count() > 0 ? round($totalHours / $workedRecords->count(), 2) : 0,
                'approved' => $records->filter(fn ($record) => $record->status === 'approved')->count(),
            ],
            'filters' => [
                'start_date' => $startDate->toDateString(),
                'end_date' => $endDate->toDateString(),
                'date' => $request->string('date')->toString(),
                'department_id' => $request->string('department_id')->toString(),
            ],
        ]);
    }

    public function clockIn(StoreAttendanceRequest $request)
    {
        $user = auth()->user() ?? $request->user();

        // Check if already clocked in
        if ($this->attendanceService->getTodayStatus($user)?->clock_in) {
            return back()->with('error', 'Already clocked in for today.');
        }

        $this->attendanceService->clockIn(
            $user,
            $request->note,
            $request->manual ?? false,
            $request->work_mode ?? 'office'
        );

        return back()->with('success', 'Clocked in successfully.');
    }

    public function startBreak(Request $request)
    {
        $user = $request->user();
        $attendance = $this->attendanceService->startBreak($user);

        if (! $attendance) {
            return back()->with('error', 'Unable to start break. Please check your attendance status.');
        }

        return back()->with('success', 'Break started successfully.');
    }

    public function endBreak(Request $request)
    {
        $user = $request->user();
        $attendance = $this->attendanceService->endBreak($user);

        if (! $attendance) {
            return back()->with('error', 'Unable to end break. Please check your attendance status.');
        }

        return back()->with('success', 'Break ended successfully.');
    }

    public function clockOut(StoreAttendanceRequest $request)
    {
        $user = $request->user();
        $status = $this->attendanceService->getTodayStatus($user);

        if (! $status || ! $status->clock_in) {
            return back()->with('error', 'Must clock in first.');
        }

        if ($status->clock_out) {
            return back()->with('error', 'Already clocked out for today.');
        }

        $this->attendanceService->clockOut(
            $user,
            $request->note,
            $request->manual ?? false
        );

        return back()->with('success', 'Clocked out successfully.');
    }

    public function manualEntry(Request $request)
    {
        $validated = $request->validate([
            'date' => 'required|date',
            'clock_in' => 'required',
            'clock_out' => 'nullable',
            'note' => 'nullable|string|max:500',
        ]);

        $this->attendanceService->storeManualEntry(
            $request->user(),
            $validated['date'],
            $validated['clock_in'],
            $validated['clock_out'],
            $validated['note']
        );

        return back()->with('success', __('Manual attendance entry submitted for approval.'));
    }
}
