<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Activity;
use App\Models\Attendance;
use App\Models\Holiday;
use App\Models\Location;
use App\Models\User;
use App\Services\ActivityAssignmentService;
use App\Services\AttendanceService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class AttendanceController extends Controller
{
    public function __construct(
        private AttendanceService $attendanceService,
        private ActivityAssignmentService $activityAssignmentService
    ) {}

    /**
     * Check in presensi harian
     */
    public function checkIn(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'address' => 'nullable|string',
            'notes' => 'nullable|string',
            'type' => 'nullable|in:office,wfh,business_trip,pusdiklat,sick,permission,leave',
            // Device info validation
            'device_id' => 'nullable|string|max:255',
            'device_model' => 'nullable|string|max:255',
            'device_brand' => 'nullable|string|max:255',
            'os_version' => 'nullable|string|max:255',
            'app_version' => 'nullable|string|max:255',
        ]);

        $result = $this->attendanceService->checkIn(
            user: $request->user(),
            latitude: $request->latitude,
            longitude: $request->longitude,
            address: $request->address,
            notes: $request->notes,
            type: $request->type ?? 'office',
            deviceInfo: [
                'device_id' => $request->device_id,
                'device_model' => $request->device_model,
                'device_brand' => $request->device_brand,
                'os_version' => $request->os_version,
                'app_version' => $request->app_version,
            ]
        );

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Check out presensi harian
     */
    public function checkOut(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'address' => 'nullable|string',
            'notes' => 'nullable|string',
            'checkout_time' => 'nullable|date_format:H:i', // Optional: jam checkout pilihan user
            // Device info validation
            'device_id' => 'nullable|string|max:255',
            'device_model' => 'nullable|string|max:255',
            'device_brand' => 'nullable|string|max:255',
            'os_version' => 'nullable|string|max:255',
            'app_version' => 'nullable|string|max:255',
        ]);

        $result = $this->attendanceService->checkOut(
            user: $request->user(),
            latitude: $request->latitude,
            longitude: $request->longitude,
            address: $request->address,
            notes: $request->notes,
            checkoutTime: $request->checkout_time,
            deviceInfo: [
                'device_id' => $request->device_id,
                'device_model' => $request->device_model,
                'device_brand' => $request->device_brand,
                'os_version' => $request->os_version,
                'app_version' => $request->app_version,
            ]
        );

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Status presensi hari ini
     */
    public function today(Request $request): JsonResponse
    {
        $status = $this->attendanceService->getTodayStatus($request->user());

        return response()->json([
            'success' => true,
            'data' => $status,
        ]);
    }

    /**
     * Riwayat presensi
     */
    public function history(Request $request): JsonResponse
    {
        $request->validate([
            'start_date' => 'nullable|date',
            'end_date' => 'nullable|date|after_or_equal:start_date',
            'limit' => 'nullable|integer|min:1|max:100',
        ]);

        $startDate = $request->start_date ? Carbon::parse($request->start_date) : null;
        $endDate = $request->end_date ? Carbon::parse($request->end_date) : null;
        $limit = $request->limit ?? 30;

        $history = $this->attendanceService->getHistory(
            user: $request->user(),
            startDate: $startDate,
            endDate: $endDate,
            limit: $limit
        );

        return response()->json([
            'success' => true,
            'data' => $history,
        ]);
    }

    /**
     * Detail presensi berdasarkan tanggal
     */
    public function show(Request $request, string $date): JsonResponse
    {
        $attendance = Attendance::where('user_id', $request->user()->id)
            ->whereDate('date', $date)
            ->with(['office', 'company', 'location', 'businessTripLocation'])
            ->first();

        if (!$attendance) {
            return response()->json([
                'success' => false,
                'message' => 'Data presensi tidak ditemukan',
            ], 404);
        }

        // Add location_name to response for easier access
        $data = $attendance->toArray();
        $data['location_name'] = $attendance->location?->name
            ?? $attendance->businessTripLocation?->name
            ?? $attendance->office?->name;

        return response()->json([
            'success' => true,
            'data' => $data,
        ]);
    }

    /**
     * Kalender presensi bulanan (semua hari termasuk absent)
     * Untuk user melihat rekap dan backdate diri sendiri
     */
    public function calendar(Request $request): JsonResponse
    {
        $request->validate([
            'month' => 'nullable|integer|between:1,12',
            'year' => 'nullable|integer|min:2020',
        ]);

        $month = $request->month ?? now()->month;
        $year = $request->year ?? now()->year;

        $calendar = $this->attendanceService->getMonthlyCalendar(
            user: $request->user(),
            year: $year,
            month: $month
        );

        return response()->json([
            'success' => true,
            'data' => [
                'month' => $month,
                'year' => $year,
                'calendar' => $calendar,
            ],
        ]);
    }

    /**
     * Statistik presensi bulanan
     */
    public function statistics(Request $request): JsonResponse
    {
        $request->validate([
            'month' => 'nullable|integer|between:1,12',
            'year' => 'nullable|integer|min:2020',
        ]);

        $month = $request->month ?? now()->month;
        $year = $request->year ?? now()->year;

        $user = $request->user();

        $attendances = Attendance::where('user_id', $user->id)
            ->whereYear('date', $year)
            ->whereMonth('date', $month)
            ->get();

        $statistics = [
            'total_days' => $attendances->count(),
            'present' => $attendances->where('status', 'present')->count(),
            'late' => $attendances->where('status', 'late')->count(),
            'early_leave' => $attendances->where('status', 'early_leave')->count(),
            'absent' => $attendances->where('status', 'absent')->count(),
            'leave' => $attendances->where('status', 'leave')->count(),
            'sick' => $attendances->where('status', 'sick')->count(),
            'permission' => $attendances->whereIn('status', ['permission', 'permit'])->count(),
            'wfh' => $attendances->where('type', 'wfh')->count(),
            'business_trip' => $attendances->where('type', 'business_trip')->count(),
            'total_work_minutes' => $attendances->sum('work_duration'),
            'total_overtime_minutes' => $attendances->sum('overtime_duration'),
        ];

        return response()->json([
            'success' => true,
            'data' => [
                'month' => $month,
                'year' => $year,
                'statistics' => $statistics,
            ],
        ]);
    }

    /**
     * List yang hadir hari ini (untuk semua role)
     * Semua user bisa melihat siapa saja yang hadir di company mereka
     */
    public function todayList(Request $request): JsonResponse
    {
        $user = $request->user();

        $query = Attendance::with(['user', 'office', 'company'])
            ->whereDate('date', today())
            ->whereNotNull('check_in_time')
            // Hide super_admin from attendance list (using Spatie roles)
            ->whereHas('user', function ($q) {
                $q->whereDoesntHave('roles', function ($r) {
                    $r->where('name', 'super_admin');
                });
            });

        // Filter by company (all users only see their own company)
        // Super admin bisa lihat semua
        if (!$user->hasRole('super_admin')) {
            $query->where('company_id', $user->company_id);
        }

        $attendances = $query->orderBy('check_in_time', 'desc')->get();

        return response()->json([
            'success' => true,
            'data' => [
                'date' => today()->format('Y-m-d'),
                'total' => $attendances->count(),
                'attendances' => $attendances->map(function ($attendance) {
                    return [
                        'id' => $attendance->id,
                        'user' => [
                            'id' => $attendance->user->id,
                            'name' => $attendance->user->name,
                            'employee_id' => $attendance->user->employee_id,
                            'nip' => $attendance->user->nip,
                            'department' => $attendance->user->department,
                            'position' => $attendance->user->position,
                        ],
                        'type' => $attendance->type,
                        'status' => $attendance->status,
                        'check_in_time' => $attendance->check_in_time?->format('H:i:s'),
                        'check_in_address' => $attendance->check_in_address,
                        'check_out_time' => $attendance->check_out_time?->format('H:i:s'),
                        'check_out_address' => $attendance->check_out_address,
                        'work_duration' => $attendance->work_duration,
                        'office' => $attendance->office ? [
                            'id' => $attendance->office->id,
                            'name' => $attendance->office->name,
                        ] : null,
                    ];
                }),
            ],
        ]);
    }

    /**
     * Get attendance status for all users on a specific date (All roles)
     * Semua role bisa melihat rekap kehadiran di company mereka
     */
    public function adminAttendanceStatus(Request $request): JsonResponse
    {
        $user = $request->user();

        $request->validate([
            'date' => 'required|date',
        ]);

        $date = Carbon::parse($request->date)->format('Y-m-d');

        // Get all active users in the same company (or all if super admin)
        // ALWAYS hide super_admin from list (using Spatie roles)
        $query = User::where('is_active', true)
            ->where('approval_status', 'approved')
            ->whereDoesntHave('roles', function ($r) {
                $r->where('name', 'super_admin');
            });

        // All users only see their own company, super admin can see all
        if (!$user->hasRole('super_admin')) {
            $query->where('company_id', $user->company_id);
        }

        $users = $query->orderBy('name')->get();

        // Get all attendances for this date in one query for better performance
        $attendances = Attendance::whereDate('date', $date)
            ->whereIn('user_id', $users->pluck('id'))
            ->get()
            ->keyBy('user_id');

        // Get all activities for this date
        $activities = Activity::whereDate('date', $date)
            ->whereIn('user_id', $users->pluck('id'))
            ->get()
            ->groupBy('user_id');

        $attendanceStatus = $users->map(function ($user) use ($date, $attendances, $activities) {
            $attendance = $attendances->get($user->id);
            $userActivities = $activities->get($user->id);

            // Determine status
            $status = 'absent';
            if ($attendance) {
                $status = $attendance->status ?? 'absent';
            }

            // Format check in/out time
            $checkIn = null;
            $checkOut = null;
            $checkInTimestamp = null; // For sorting by time
            if ($attendance && $attendance->check_in_time) {
                $checkIn = $attendance->check_in_time->format('H:i:s');
                $checkInTimestamp = $attendance->check_in_time->timestamp; // Use timestamp for proper sorting
            }
            if ($attendance && $attendance->check_out_time) {
                $checkOut = $attendance->check_out_time->format('H:i:s');
            }

            // Check if activity is filled
            $activityFilled = $userActivities && $userActivities->isNotEmpty();

            // Determine if absent (no attendance or status is absent)
            $isAbsent = !$attendance || $status === 'absent';

            // Get avatar URL - stored directly in public/avatars (no symlink needed)
            $avatarUrl = null;
            if ($user->avatar) {
                // If avatar is a full URL, use it directly
                if (filter_var($user->avatar, FILTER_VALIDATE_URL)) {
                    $avatarUrl = $user->avatar;
                } else {
                    // Avatar stored directly in public folder
                    $avatarUrl = asset($user->avatar);
                }
            }

            return [
                'id' => $attendance ? $attendance->id : null,
                'user_id' => $user->id,
                'name' => $user->name,
                'position' => $user->position ?? null, // Jabatan
                'department' => $user->department ?? null, // Departemen
                'avatar' => $avatarUrl, // Foto
                'status' => $status, // present, late, absent, sick, leave, permit
                'type' => $attendance?->type ?? null, // office, wfh, business_trip, sick, permission, leave
                'check_in' => $checkIn,
                'check_out' => $checkOut,
                'activity_filled' => $activityFilled,
                'location_name' => $attendance?->location?->name ?? $attendance?->office?->name ?? null,
                '_sort_key' => [
                    'is_absent' => $isAbsent ? 0 : 1, // 0 = absent first, 1 = has attendance
                    'check_in_timestamp' => $checkInTimestamp ?? PHP_INT_MAX, // No check in = last
                ],
            ];
        });

        // Sort: absent first (is_absent = 0), then by check_in_time (ascending)
        $sortedStatus = $attendanceStatus->sortBy([
            ['_sort_key.is_absent', 'asc'], // Absent (0) comes first
            ['_sort_key.check_in_timestamp', 'asc'], // Then sort by check_in_time (earliest first)
        ])->values()->map(function ($item) {
            // Remove sort key from response
            unset($item['_sort_key']);
            return $item;
        });

        // Add cache control headers to prevent caching
        return response()->json([
            'success' => true,
            'date' => $date,
            'total_users' => $users->count(),
            'total_present' => $sortedStatus->filter(fn($item) => in_array($item['status'], ['present', 'late']))->count(),
            'total_absent' => $sortedStatus->filter(fn($item) => $item['status'] === 'absent')->count(),
            'attendance_status' => $sortedStatus->all(),
            'timestamp' => now()->toIso8601String(),
        ])->header('Cache-Control', 'no-cache, no-store, must-revalidate')
          ->header('Pragma', 'no-cache')
          ->header('Expires', '0');
    }

    /**
     * Get list of attendances that are missing activities (for current user)
     * Returns dates where user has checked in but hasn't filled activities
     */
    public function missingActivities(Request $request): JsonResponse
    {
        $user = $request->user();

        // If activity is not mandatory for this user, return empty
        try {
            if (!$this->activityAssignmentService->isActivityMandatoryForUser($user)) {
                return response()->json([
                    'success' => true,
                    'data' => [],
                    'count' => 0,
                    'activity_mandatory' => false,
                ]);
            }
        } catch (\Exception $e) {
            \Log::warning('missingActivities mandatory check error: ' . $e->getMessage());
        }

        // Get all attendances where user has checked in but date has passed
        $today = Carbon::today();

        $attendances = Attendance::where('user_id', $user->id)
            ->whereNotNull('check_in_time')
            ->whereDate('date', '<', $today) // Only past dates
            ->orderBy('date', 'desc')
            ->get();

        // Get all activities for these attendances
        $activityDates = Activity::where('user_id', $user->id)
            ->whereIn('attendance_id', $attendances->pluck('id'))
            ->pluck('date')
            ->map(function ($date) {
                return Carbon::parse($date)->format('Y-m-d');
            })
            ->unique()
            ->toArray();

        // Filter attendances that don't have activities
        // Exclude sick/permission/leave types as they don't require activity
        $missingActivities = $attendances->filter(function ($attendance) use ($activityDates) {
            // Skip sick, permission, leave - they don't need activity
            if (in_array($attendance->type, ['sick', 'permission', 'leave'])) {
                return false;
            }
            $attendanceDate = $attendance->date->format('Y-m-d');
            return !in_array($attendanceDate, $activityDates);
        })->map(function ($attendance) {
            return [
                'id' => $attendance->id,
                'date' => $attendance->date->format('Y-m-d'),
                'date_display' => $attendance->date->format('d M Y'),
                'check_in_time' => $attendance->check_in_time ? $attendance->check_in_time->format('H:i') : null,
                'check_out_time' => $attendance->check_out_time ? $attendance->check_out_time->format('H:i') : null,
                'status' => $attendance->status,
            ];
        })->values();

        return response()->json([
            'success' => true,
            'data' => $missingActivities->all(),
            'count' => $missingActivities->count(),
            'activity_mandatory' => true,
        ]);
    }

    /**
     * Check if today's attendance is missing activity (for current user)
     */
    public function todayMissingActivity(Request $request): JsonResponse
    {
        $user = $request->user();

        // If activity is not mandatory for this user, never flag as missing
        $isActivityMandatory = false;
        try {
            $isActivityMandatory = $this->activityAssignmentService->isActivityMandatoryForUser($user);
        } catch (\Exception $e) {
            \Log::warning('todayMissingActivity mandatory check error: ' . $e->getMessage());
        }

        if (!$isActivityMandatory) {
            return response()->json([
                'success' => true,
                'has_attendance' => false,
                'missing_activity' => false,
                'activity_mandatory' => false,
            ]);
        }

        $today = Carbon::today();

        $attendance = Attendance::where('user_id', $user->id)
            ->whereDate('date', $today)
            ->whereNotNull('check_in_time')
            ->first();

        if (!$attendance) {
            return response()->json([
                'success' => true,
                'has_attendance' => false,
                'missing_activity' => false,
                'activity_mandatory' => true,
            ]);
        }

        // Sick/permission/leave don't require activity
        if (in_array($attendance->type, ['sick', 'permission', 'leave'])) {
            return response()->json([
                'success' => true,
                'has_attendance' => true,
                'missing_activity' => false, // Never missing for absence types
                'attendance_id' => $attendance->id,
                'activity_mandatory' => true,
            ]);
        }

        $hasActivity = Activity::where('user_id', $user->id)
            ->where('attendance_id', $attendance->id)
            ->exists();

        return response()->json([
            'success' => true,
            'has_attendance' => true,
            'missing_activity' => !$hasActivity,
            'attendance_id' => $attendance->id,
            'activity_mandatory' => true,
        ]);
    }

    /**
     * Get list of users who are missing/absent on a specific date (All roles)
     */
    public function adminAttendanceMissing(Request $request): JsonResponse
    {
        $user = $request->user();

        $request->validate([
            'date' => 'required|date',
        ]);

        $date = Carbon::parse($request->date);

        // Get all active users in the same company (or all if super admin)
        // ALWAYS hide super_admin from list (using Spatie roles)
        $query = User::where('is_active', true)
            ->where('approval_status', 'approved')
            ->whereDoesntHave('roles', function ($r) {
                $r->where('name', 'super_admin');
            });

        // All users only see their own company, super admin can see all
        if (!$user->hasRole('super_admin')) {
            $query->where('company_id', $user->company_id);
        }

        $users = $query->get();

        $missingAttendance = $users->filter(function ($userItem) use ($date) {
            $attendance = Attendance::where('user_id', $userItem->id)
                ->whereDate('date', $date)
                ->first();

            // Missing if no attendance or status is absent
            return !$attendance || $attendance->status === 'absent';
        })->map(function ($userItem) use ($date) {
            $attendance = Attendance::where('user_id', $userItem->id)
                ->whereDate('date', $date)
                ->first();

            return [
                'user_id' => $userItem->id,
                'name' => $userItem->name,
                'status' => $attendance ? $attendance->status : 'absent',
            ];
        });

        return response()->json([
            'missing_attendance' => $missingAttendance->values()->all(),
        ]);
    }

    /**
     * Check if a date is within the editable period (before cutoff)
     */
    private function isWithinEditablePeriod(Carbon $targetDate): bool
    {
        $now = Carbon::now();

        // Get the cutoff date for the target month
        // Cutoff is the 10th of the month AFTER the target date's month
        $cutoffDate = $targetDate->copy()
            ->addMonth()
            ->startOfMonth()
            ->addDays(9) // 10th of the month (0-indexed would be 9)
            ->endOfDay();

        return $now->lte($cutoffDate);
    }

    public function backdateAttendance(Request $request): JsonResponse
    {
        $user = $request->user();
        $company = $user->company;

        // Check if historical entry is enabled
        if (!$company->backdate_enabled) {
            return response()->json([
                'success' => false,
                'message' => 'Fitur pengisian presensi tidak diaktifkan',
            ], 403);
        }

        $request->validate([
            'user_id' => 'nullable|exists:users,id',
            'date' => 'required|date|before_or_equal:today',
            'type' => 'required|in:office,wfh,business_trip,pusdiklat,sick,permission,leave',
            'check_in_time' => 'required|date_format:H:i',
            'check_out_time' => 'nullable|date_format:H:i|after:check_in_time',
            'check_in_latitude' => 'nullable|numeric|between:-90,90',
            'check_in_longitude' => 'nullable|numeric|between:-180,180',
            'check_out_latitude' => 'nullable|numeric|between:-90,90',
            'check_out_longitude' => 'nullable|numeric|between:-180,180',
            'check_in_address' => 'nullable|string',
            'check_out_address' => 'nullable|string',
            'notes' => 'nullable|string',
            'status' => 'nullable|in:present,late,early_leave,absent,sick,permission,leave',
            'location_id' => 'nullable|exists:locations,id',
        ]);

        // Determine target user
        $targetUserId = $request->user_id ?? $user->id;
        $targetUser = User::findOrFail($targetUserId);

        // Check permission: user can only fill their own attendance
        $isOwnAttendance = $targetUserId == $user->id;
        if (!$isOwnAttendance && !$user->hasRole('super_admin')) {
            return response()->json([
                'success' => false,
                'message' => 'Anda hanya dapat mengisi presensi untuk diri sendiri',
            ], 403);
        }

        $date = Carbon::parse($request->date);

        // Check cutoff period
        if (!$this->isWithinEditablePeriod($date)) {
            $cutoffDate = $date->copy()->addMonth()->startOfMonth()->addDays(9);
            return response()->json([
                'success' => false,
                'message' => 'Periode sudah melewati batas waktu edit (cutoff tanggal ' . $cutoffDate->format('d M Y') . ')',
            ], 403);
        }

        // Check if attendance already exists for this date
        $existingAttendance = Attendance::where('user_id', $targetUserId)
            ->whereDate('date', $date)
            ->first();

        // If attendance exists (complete or incomplete), update it
        if ($existingAttendance) {
            // Update existing attendance
            $checkInTime = $request->check_in_time
                ? Carbon::parse($date->format('Y-m-d') . ' ' . $request->check_in_time)
                : $existingAttendance->check_in_time;
            $checkOutTime = $request->check_out_time
                ? Carbon::parse($date->format('Y-m-d') . ' ' . $request->check_out_time)
                : null;

            $workDuration = $checkOutTime ? $checkInTime->diffInMinutes($checkOutTime) : null;

            // Determine status
            $status = $request->status ?? $existingAttendance->status;
            if (in_array($request->type, ['sick', 'permission', 'leave'])) {
                $status = $request->type;
            }

            // Get device info from user's registered device
            $deviceInfo = \App\Models\UserDevice::getDeviceInfoForBackdate($targetUserId);

            $updateData = [
                'type' => $request->type ?? $existingAttendance->type,
                'status' => $status,
                'check_in_time' => $checkInTime,
                'check_out_time' => $checkOutTime,
                'check_in_latitude' => $request->check_in_latitude ?? $existingAttendance->check_in_latitude,
                'check_in_longitude' => $request->check_in_longitude ?? $existingAttendance->check_in_longitude,
                'check_out_latitude' => $request->check_out_latitude ?? $existingAttendance->check_out_latitude,
                'check_out_longitude' => $request->check_out_longitude ?? $existingAttendance->check_out_longitude,
                'check_in_address' => $request->check_in_address ?? $existingAttendance->check_in_address,
                'check_out_address' => $request->check_out_address ?? $existingAttendance->check_out_address,
                'check_in_notes' => $request->notes ?? $existingAttendance->check_in_notes,
                'work_duration' => $workDuration,
            ];

            // Update location_id if provided
            if ($request->has('location_id')) {
                $updateData['location_id'] = $request->location_id;
            }

            // Add device info if not already present
            if (!$existingAttendance->check_in_device_model) {
                $updateData['check_in_device_model'] = $deviceInfo['device_model'];
                $updateData['check_in_device_brand'] = $deviceInfo['device_brand'];
                $updateData['check_in_os_version'] = $deviceInfo['os_version'];
                $updateData['check_in_app_version'] = $deviceInfo['app_version'];
            }

            // Add checkout device info if checking out
            if ($checkOutTime && !$existingAttendance->check_out_device_model) {
                $updateData['check_out_device_model'] = $deviceInfo['device_model'];
                $updateData['check_out_device_brand'] = $deviceInfo['device_brand'];
                $updateData['check_out_os_version'] = $deviceInfo['os_version'];
                $updateData['check_out_app_version'] = $deviceInfo['app_version'];
            }

            $existingAttendance->update($updateData);

            // Log activity record
            $actionNote = $isOwnAttendance
                ? 'Diperbarui oleh: ' . $user->name
                : 'Diperbarui untuk: ' . $targetUser->name;

            \App\Models\ActivityRecord::log(
                userId: $user->id,
                action: 'update',
                entityType: 'attendance',
                entityId: $existingAttendance->id,
                targetDate: $date->format('Y-m-d'),
                newValues: [
                    'target_user_id' => $targetUserId,
                    'target_user_name' => $targetUser->name,
                    'type' => $request->type ?? $existingAttendance->type,
                    'status' => $status,
                    'check_in_time' => $checkInTime->format('H:i'),
                    'check_out_time' => $checkOutTime?->format('H:i'),
                ],
                attendanceId: $existingAttendance->id,
                notes: $actionNote
            );

            return response()->json([
                'success' => true,
                'message' => 'Presensi berhasil diperbarui',
                'data' => $existingAttendance->fresh()->load(['user', 'office', 'company']),
            ]);
        }

        // Parse times
        $checkInTime = Carbon::parse($date->format('Y-m-d') . ' ' . $request->check_in_time);
        $checkOutTime = $request->check_out_time
            ? Carbon::parse($date->format('Y-m-d') . ' ' . $request->check_out_time)
            : null;

        // Calculate work duration
        $workDuration = $checkOutTime ? $checkInTime->diffInMinutes($checkOutTime) : null;

        // Determine status based on type
        $status = $request->status ?? 'present';
        if (in_array($request->type, ['sick', 'permission', 'leave'])) {
            $status = $request->type;
        }

        // Get device info from user's registered device
        $deviceInfo = \App\Models\UserDevice::getDeviceInfoForBackdate($targetUserId);

        // Create attendance with device info
        $attendance = Attendance::create([
            'user_id' => $targetUserId,
            'company_id' => $targetUser->company_id,
            'location_id' => $request->location_id,
            'date' => $date,
            'type' => $request->type,
            'status' => $status,
            'check_in_time' => $checkInTime,
            'check_out_time' => $checkOutTime,
            'check_in_latitude' => $request->check_in_latitude,
            'check_in_longitude' => $request->check_in_longitude,
            'check_out_latitude' => $request->check_out_latitude,
            'check_out_longitude' => $request->check_out_longitude,
            'check_in_address' => $request->check_in_address,
            'check_out_address' => $request->check_out_address,
            'check_in_notes' => $request->notes,
            'work_duration' => $workDuration,
            // Device info dari user's registered device
            'check_in_device_model' => $deviceInfo['device_model'],
            'check_in_device_brand' => $deviceInfo['device_brand'],
            'check_in_os_version' => $deviceInfo['os_version'],
            'check_in_app_version' => $deviceInfo['app_version'],
            // Checkout device info (sama dengan check-in untuk konsistensi)
            'check_out_device_model' => $checkOutTime ? $deviceInfo['device_model'] : null,
            'check_out_device_brand' => $checkOutTime ? $deviceInfo['device_brand'] : null,
            'check_out_os_version' => $checkOutTime ? $deviceInfo['os_version'] : null,
            'check_out_app_version' => $checkOutTime ? $deviceInfo['app_version'] : null,
        ]);

        // Log activity record
        $actionNote = $isOwnAttendance
            ? 'Dibuat oleh: ' . $user->name
            : 'Dibuat untuk: ' . $targetUser->name;

        \App\Models\ActivityRecord::log(
            userId: $user->id,
            action: 'create',
            entityType: 'attendance',
            entityId: $attendance->id,
            targetDate: $date->format('Y-m-d'),
            newValues: [
                'target_user_id' => $targetUserId,
                'target_user_name' => $targetUser->name,
                'type' => $request->type,
                'status' => $status,
                'check_in_time' => $checkInTime->format('H:i'),
                'check_out_time' => $checkOutTime?->format('H:i'),
            ],
            attendanceId: $attendance->id,
            notes: $actionNote
        );

        return response()->json([
            'success' => true,
            'message' => 'Presensi backdate berhasil dibuat',
            'data' => $attendance->load(['user', 'office', 'company']),
        ]);
    }

    /**
     * Update attendance - User can update own attendance, Admin can update anyone's
     * Must be within cutoff period and backdate must be enabled
     */
    public function updateAttendance(Request $request, Attendance $attendance): JsonResponse
    {
        $user = $request->user();
        $company = $user->company;

        // Check if backdate is enabled (required for editing past attendance)
        if (!$company->backdate_enabled) {
            return response()->json([
                'success' => false,
                'message' => 'Fitur edit presensi tidak diaktifkan',
            ], 403);
        }

        // Check permission: user can only update their own attendance, super_admin can update anyone's
        $isOwnAttendance = $attendance->user_id == $user->id;
        if (!$isOwnAttendance && !$user->hasRole('super_admin')) {
            return response()->json([
                'success' => false,
                'message' => 'Anda hanya dapat mengedit presensi milik Anda sendiri',
            ], 403);
        }

        // Check cutoff period
        $attendanceDate = Carbon::parse($attendance->date);
        if (!$this->isWithinEditablePeriod($attendanceDate)) {
            $cutoffDate = $attendanceDate->copy()->addMonth()->startOfMonth()->addDays(9);
            return response()->json([
                'success' => false,
                'message' => 'Periode sudah melewati batas waktu edit (cutoff tanggal ' . $cutoffDate->format('d M Y') . ')',
            ], 403);
        }

        // Check if location is editable
        $canEditLocation = $company->allow_editable_location ?? false;

        $request->validate([
            'type' => 'nullable|in:office,wfh,business_trip,pusdiklat,sick,permission,leave',
            'status' => 'nullable|in:present,late,early_leave,absent,sick,permission,leave',
            'check_in_time' => 'nullable|date_format:H:i',
            'check_out_time' => 'nullable|date_format:H:i',
            'check_in_latitude' => 'nullable|numeric|between:-90,90',
            'check_in_longitude' => 'nullable|numeric|between:-180,180',
            'check_out_latitude' => 'nullable|numeric|between:-90,90',
            'check_out_longitude' => 'nullable|numeric|between:-180,180',
            'check_in_address' => 'nullable|string',
            'check_out_address' => 'nullable|string',
            'notes' => 'nullable|string',
            'location_id' => 'nullable|integer|exists:locations,id',
        ]);

        // Store old values
        $oldValues = $attendance->only([
            'type', 'status', 'check_in_time', 'check_out_time',
            'check_in_address', 'check_out_address', 'work_duration'
        ]);

        $updateData = [];

        if ($request->has('type')) {
            $updateData['type'] = $request->type;
        }

        if ($request->has('status')) {
            $updateData['status'] = $request->status;
        }

        if ($request->has('check_in_time')) {
            $updateData['check_in_time'] = Carbon::parse(
                $attendance->date->format('Y-m-d') . ' ' . $request->check_in_time
            );
        }

        if ($request->has('check_out_time')) {
            $updateData['check_out_time'] = $request->check_out_time
                ? Carbon::parse($attendance->date->format('Y-m-d') . ' ' . $request->check_out_time)
                : null;
        }

        // Only allow location edit if enabled
        if ($canEditLocation) {
            if ($request->has('check_in_latitude')) {
                $updateData['check_in_latitude'] = $request->check_in_latitude;
            }
            if ($request->has('check_in_longitude')) {
                $updateData['check_in_longitude'] = $request->check_in_longitude;
            }
            if ($request->has('check_out_latitude')) {
                $updateData['check_out_latitude'] = $request->check_out_latitude;
            }
            if ($request->has('check_out_longitude')) {
                $updateData['check_out_longitude'] = $request->check_out_longitude;
            }
            if ($request->has('check_in_address')) {
                $updateData['check_in_address'] = $request->check_in_address;
            }
            if ($request->has('check_out_address')) {
                $updateData['check_out_address'] = $request->check_out_address;
            }
            if ($request->has('location_id')) {
                $updateData['location_id'] = $request->location_id;
            }
        }

        if ($request->has('notes')) {
            $updateData['check_in_notes'] = $request->notes;
        }

        // Recalculate work duration if times changed
        if (isset($updateData['check_in_time']) || isset($updateData['check_out_time'])) {
            $checkIn = $updateData['check_in_time'] ?? $attendance->check_in_time;
            $checkOut = $updateData['check_out_time'] ?? $attendance->check_out_time;
            if ($checkIn && $checkOut) {
                $updateData['work_duration'] = Carbon::parse($checkIn)->diffInMinutes(Carbon::parse($checkOut));
            }
        }

        $attendance->update($updateData);

        // Log activity record
        $actionNote = $isOwnAttendance
            ? 'Diedit oleh: ' . $user->name
            : 'Diedit untuk: ' . $attendance->user->name;

        \App\Models\ActivityRecord::log(
            userId: $user->id,
            action: 'update',
            entityType: 'attendance',
            entityId: $attendance->id,
            targetDate: $attendance->date->format('Y-m-d'),
            oldValues: $oldValues,
            newValues: $attendance->only([
                'type', 'status', 'check_in_time', 'check_out_time',
                'check_in_address', 'check_out_address', 'work_duration'
            ]),
            attendanceId: $attendance->id,
            notes: $actionNote
        );

        return response()->json([
            'success' => true,
            'message' => 'Presensi berhasil diperbarui',
            'data' => $attendance->fresh()->load(['user', 'office', 'company']),
        ]);
    }

    /**
     * Get red flags for user - issues that need attention
     * Red flags include:
     * - Missing attendance (working day without check-in)
     * - Missing checkout (checked in but didn't check out)
     * - Wrong location (check-in location doesn't match expected office)
     * - Missing activities (attendance exists but no activities filled)
     * - Business trip without coordinates
     *
     * Period: Last 2 months until today
     * Activity red flags: Always shown (regardless of editable/backdate settings)
     * Other red flags: Only shown if editable=true AND backdate=true
     */
    public function getRedFlags(Request $request): JsonResponse
    {
        $user = $request->user();
        $company = $user->company;

        if (!$company) {
            return response()->json([
                'success' => true,
                'red_flags' => [],
                'count' => 0,
            ]);
        }

        $redFlags = [];

        // Check if activity is mandatory for this user
        $isActivityMandatory = false;
        try {
            $isActivityMandatory = $this->activityAssignmentService->isActivityMandatoryForUser($user);
        } catch (\Exception $e) {
            \Log::warning('isActivityMandatoryForUser error: ' . $e->getMessage());
        }

        // Settings
        $isEditable = $company->allow_editable_location ?? false;
        $isBackdateEnabled = $company->backdate_enabled ?? false;
        // Show editable flags (missing attendance, missing checkout) only if both settings are enabled
        $showEditableFlags = $isEditable && $isBackdateEnabled;
        // Show location anomaly flags if backdate is enabled (user can fix via backdate sheet)
        $showLocationFlags = $isBackdateEnabled;

        // Period: 2 months ago until today
        $startDate = Carbon::now()->subMonths(2)->startOfDay();
        $endDate = Carbon::today();

        // Get holidays for the period
        // Include: company-specific holidays, global holidays (company_id = null), and recurring holidays
        $holidays = Holiday::where('is_active', true)
            ->where(function ($q) use ($company) {
                $q->whereNull('company_id')
                    ->orWhere('company_id', $company->id);
            })
            ->get()
            ->filter(function ($holiday) use ($startDate, $endDate) {
                // For recurring holidays, check if the month/day falls within the period
                if ($holiday->is_recurring) {
                    // Check each year in the period
                    $currentYear = $startDate->year;
                    $endYear = $endDate->year;

                    for ($year = $currentYear; $year <= $endYear; $year++) {
                        $recurringDate = Carbon::create($year, $holiday->date->month, $holiday->date->day);
                        if ($recurringDate->between($startDate, $endDate)) {
                            return true;
                        }
                    }
                    return false;
                }

                // For non-recurring, check if date is within period
                return $holiday->date->between($startDate, $endDate);
            })
            ->flatMap(function ($holiday) use ($startDate, $endDate) {
                // For recurring holidays, generate dates for each year in period
                if ($holiday->is_recurring) {
                    $dates = [];
                    $currentYear = $startDate->year;
                    $endYear = $endDate->year;

                    for ($year = $currentYear; $year <= $endYear; $year++) {
                        $recurringDate = Carbon::create($year, $holiday->date->month, $holiday->date->day);
                        if ($recurringDate->between($startDate, $endDate)) {
                            $dates[] = $recurringDate->format('Y-m-d');
                        }
                    }
                    return $dates;
                }

                return [$holiday->date->format('Y-m-d')];
            })
            ->unique()
            ->toArray();

        // Weekend days
        $weekendDays = $company->weekend_days ?? [0, 6]; // Sunday (0) and Saturday (6)

        // Get all attendances in the period
        $attendances = Attendance::where('user_id', $user->id)
            ->whereBetween('date', [$startDate, $endDate])
            ->with(['location', 'office', 'businessTripLocation', 'activities'])
            ->get()
            ->keyBy(fn($a) => $a->date->format('Y-m-d'));

        // Get all activities in the period
        $activitiesByDate = Activity::where('user_id', $user->id)
            ->whereBetween('date', [$startDate, $endDate])
            ->get()
            ->groupBy(fn($a) => Carbon::parse($a->date)->format('Y-m-d'));

        // Loop through each day in the period
        $currentDate = $startDate->copy();
        while ($currentDate->lte($endDate)) {
            $dateStr = $currentDate->format('Y-m-d');
            $dayOfWeek = $currentDate->dayOfWeek;
            $isWeekend = in_array($dayOfWeek, $weekendDays);
            $isHoliday = in_array($dateStr, $holidays);
            $isToday = $currentDate->isSameDay($endDate);
            $isWorkingDay = !$isWeekend && !$isHoliday;

            $attendance = $attendances->get($dateStr);
            $hasActivities = isset($activitiesByDate[$dateStr]) && $activitiesByDate[$dateStr]->isNotEmpty();

            // Skip if not a working day and no attendance
            if (!$isWorkingDay && !$attendance) {
                $currentDate->addDay();
                continue;
            }

            // 1. RED FLAG: Missing attendance on working day (only if showEditableFlags)
            if ($showEditableFlags && $isWorkingDay && !$attendance && !$isToday) {
                $redFlags[] = [
                    'type' => 'missing_attendance',
                    'severity' => 'high',
                    'date' => $dateStr,
                    'date_display' => $currentDate->locale('id')->isoFormat('D MMM Y'),
                    'title' => 'Lupa Absen',
                    'description' => 'Tidak ada data kehadiran',
                    'action' => 'backdate',
                    'action_label' => 'Isi Kehadiran',
                    'icon' => 'calendar_today',
                    'color' => 'red',
                ];
            }

            // If there's attendance, check for other issues
            if ($attendance) {
                $isAbsenceType = in_array($attendance->type, ['sick', 'permission', 'leave']);

                // 2. RED FLAG: Missing checkout (only if showEditableFlags and not today and not absence type and working day)
                if ($showEditableFlags && !$isToday && !$isAbsenceType && $isWorkingDay && $attendance->check_in_time && !$attendance->check_out_time) {
                    $redFlags[] = [
                        'type' => 'missing_checkout',
                        'severity' => 'medium',
                        'date' => $dateStr,
                        'date_display' => $currentDate->locale('id')->isoFormat('D MMM Y'),
                        'title' => 'Belum Checkout',
                        'description' => 'Check-in ' . $attendance->check_in_time->format('H:i') . ' tapi belum checkout',
                        'action' => 'edit_attendance',
                        'action_label' => 'Lengkapi',
                        'attendance_id' => $attendance->id,
                        'icon' => 'logout',
                        'color' => 'orange',
                    ];
                }

                // 3. RED FLAG: Wrong location - check-in AND checkout location mismatch
                // NOTE: Tidak perlu cek isWorkingDay karena jika user sudah absen (ada attendance record),
                // maka titik lokasi tetap harus benar terlepas dari hari libur atau tidak
                // Untuk office type: gunakan headquarters/primary location dari company
                // Untuk pusdiklat type: gunakan pusdiklat location dari company
                // Untuk business_trip type: gunakan location dari location_id
                if ($showLocationFlags && !$isAbsenceType && in_array($attendance->type, ['office', 'pusdiklat', 'business_trip'])) {
                    $expectedLocation = null;

                    if ($attendance->type === 'office') {
                        // Cari lokasi kantor: prioritas headquarters/primary, fallback ke lokasi aktif manapun
                        $expectedLocation = Location::where('company_id', $attendance->company_id)
                            ->where('is_active', true)
                            ->where(function ($q) {
                                $q->where('type', 'headquarters')
                                  ->orWhere('is_primary', true);
                            })
                            ->first();

                        // Fallback: jika tidak ada headquarters/primary, cari lokasi office aktif manapun
                        if (!$expectedLocation) {
                            $expectedLocation = Location::where('company_id', $attendance->company_id)
                                ->where('is_active', true)
                                ->whereIn('type', ['headquarters', 'branch', 'office'])
                                ->first();
                        }
                    } elseif ($attendance->type === 'pusdiklat') {
                        $expectedLocation = Location::where('company_id', $attendance->company_id)
                            ->where('is_active', true)
                            ->where('type', 'pusdiklat')
                            ->first();
                    } else {
                        // business_trip: gunakan location dari attendance
                        $expectedLocation = $attendance->location;
                    }

                    if ($expectedLocation && $expectedLocation->latitude && $expectedLocation->longitude) {
                        $radius = $expectedLocation->radius ?? 100;
                        // Threshold untuk deteksi anomali: 200m
                        // Lebih longgar dari radius check-in karena:
                        // 1. Random offset di mobile (10-50m)
                        // 2. Variasi GPS device (10-30m)
                        // 3. Kondisi GPS tidak ideal (indoor, cuaca)
                        // Total deviasi wajar bisa ~80m, threshold 200m cukup aman
                        $anomalyThreshold = 200;

                        $locationTypeLabel = match ($attendance->type) {
                            'business_trip' => 'Dinas',
                            'pusdiklat' => 'Pusdiklat',
                            default => 'Kantor',
                        };

                        $hasCheckinAnomaly = false;
                        $hasCheckoutAnomaly = false;
                        $checkinDistance = 0;
                        $checkoutDistance = 0;

                        // Cek anomali check-in
                        // Deteksi jika jarak lebih dari threshold anomali (200m)
                        if ($attendance->check_in_latitude && $attendance->check_in_longitude) {
                            $checkinDistance = $this->calculateDistance(
                                $attendance->check_in_latitude,
                                $attendance->check_in_longitude,
                                $expectedLocation->latitude,
                                $expectedLocation->longitude
                            );
                            $hasCheckinAnomaly = $checkinDistance > $anomalyThreshold;
                        }

                        // Cek anomali checkout
                        // Deteksi jika jarak lebih dari threshold anomali (200m)
                        if ($attendance->check_out_latitude && $attendance->check_out_longitude) {
                            $checkoutDistance = $this->calculateDistance(
                                $attendance->check_out_latitude,
                                $attendance->check_out_longitude,
                                $expectedLocation->latitude,
                                $expectedLocation->longitude
                            );
                            $hasCheckoutAnomaly = $checkoutDistance > $anomalyThreshold;
                        }

                        // Jika ada anomali check-in atau checkout, tambah red flag
                        if ($hasCheckinAnomaly || $hasCheckoutAnomaly) {
                            $anomalyParts = [];
                            if ($hasCheckinAnomaly) {
                                $anomalyParts[] = 'check-in';
                            }
                            if ($hasCheckoutAnomaly) {
                                $anomalyParts[] = 'checkout';
                            }

                            $flagData = [
                                'type' => 'wrong_location',
                                'severity' => 'medium',
                                'date' => $dateStr,
                                'date_display' => $currentDate->locale('id')->isoFormat('D MMM Y'),
                                'title' => "Titik {$locationTypeLabel} Perlu Diperbaiki",
                                'description' => 'Titik ' . implode(' & ', $anomalyParts) . ' di luar area',
                                'action' => 'edit_attendance',
                                'action_label' => 'Perbaiki',
                                'attendance_id' => $attendance->id,
                                'icon' => 'location_off',
                                'color' => 'orange',
                                'expected_location' => [
                                    'id' => $expectedLocation->id,
                                    'name' => $expectedLocation->name,
                                    'latitude' => $expectedLocation->latitude,
                                    'longitude' => $expectedLocation->longitude,
                                    'radius' => $radius,
                                ],
                            ];

                            // Tambah data check-in location jika anomali
                            if ($hasCheckinAnomaly) {
                                $flagData['wrong_checkin_location'] = [
                                    'latitude' => $attendance->check_in_latitude,
                                    'longitude' => $attendance->check_in_longitude,
                                    'address' => $attendance->check_in_address,
                                    'distance' => round($checkinDistance),
                                ];
                            }

                            // Tambah data checkout location jika anomali
                            if ($hasCheckoutAnomaly) {
                                $flagData['wrong_checkout_location'] = [
                                    'latitude' => $attendance->check_out_latitude,
                                    'longitude' => $attendance->check_out_longitude,
                                    'address' => $attendance->check_out_address,
                                    'distance' => round($checkoutDistance),
                                ];
                            }

                            $redFlags[] = $flagData;
                        }
                    }
                }

                // 4. RED FLAG: Business trip without coordinates (only if showEditableFlags and working day)
                if ($showEditableFlags && $isWorkingDay && $attendance->type === 'business_trip') {
                    $btLocation = $attendance->businessTripLocation;
                    if ($btLocation && (!$btLocation->latitude || !$btLocation->longitude)) {
                        $redFlags[] = [
                            'type' => 'business_trip_no_coords',
                            'severity' => 'low',
                            'date' => $dateStr,
                            'date_display' => $currentDate->locale('id')->isoFormat('D MMM Y'),
                            'title' => 'Lokasi Dinas Belum Lengkap',
                            'description' => "Lokasi '{$btLocation->name}' belum ada koordinat",
                            'action' => 'view_attendance',
                            'action_label' => 'Lihat',
                            'attendance_id' => $attendance->id,
                            'icon' => 'map',
                            'color' => 'yellow',
                        ];
                    }
                }

                // 5. RED FLAG: Missing activities - ONLY for users with mandatory activity
                // Users without mandatory activity should NOT get red flags for missing activities
                // Skip today, absence types, weekends, holidays, and if already has activities
                if ($isActivityMandatory && !$isToday && !$isAbsenceType && !$hasActivities && $attendance->check_in_time && $isWorkingDay) {
                    $redFlags[] = [
                        'type' => 'missing_activity',
                        'severity' => 'high',
                        'date' => $dateStr,
                        'date_display' => $currentDate->locale('id')->isoFormat('D MMM Y'),
                        'title' => 'Aktivitas Belum Diisi',
                        'description' => 'Kehadiran tercatat tapi aktivitas belum diisi (wajib)',
                        'action' => 'fill_activity',
                        'action_label' => 'Isi Aktivitas',
                        'attendance_id' => $attendance->id,
                        'icon' => 'assignment_late',
                        'color' => 'red',
                    ];
                }
            }

            $currentDate->addDay();
        }

        // Sort by date descending (newest first)
        usort($redFlags, fn($a, $b) => strcmp($b['date'], $a['date']));

        // Summary by type
        $summary = [
            'missing_attendance' => count(array_filter($redFlags, fn($f) => $f['type'] === 'missing_attendance')),
            'missing_checkout' => count(array_filter($redFlags, fn($f) => $f['type'] === 'missing_checkout')),
            'wrong_location' => count(array_filter($redFlags, fn($f) => $f['type'] === 'wrong_location')),
            'missing_activity' => count(array_filter($redFlags, fn($f) => $f['type'] === 'missing_activity')),
            'business_trip_no_coords' => count(array_filter($redFlags, fn($f) => $f['type'] === 'business_trip_no_coords')),
        ];

        return response()->json([
            'success' => true,
            'red_flags' => $redFlags,
            'count' => count($redFlags),
            'summary' => $summary,
            'settings' => [
                'editable' => $isEditable,
                'backdate_enabled' => $isBackdateEnabled,
                'show_editable_flags' => $showEditableFlags,
                'show_location_flags' => $showLocationFlags,
                'activity_mandatory' => $isActivityMandatory,
            ],
        ]);
    }

    /**
     * Calculate distance between two coordinates in meters
     */
    private function calculateDistance(float $lat1, float $lon1, float $lat2, float $lon2): float
    {
        $earthRadius = 6371000; // meters

        $lat1Rad = deg2rad($lat1);
        $lat2Rad = deg2rad($lat2);
        $deltaLat = deg2rad($lat2 - $lat1);
        $deltaLon = deg2rad($lon2 - $lon1);

        $a = sin($deltaLat / 2) * sin($deltaLat / 2) +
            cos($lat1Rad) * cos($lat2Rad) *
            sin($deltaLon / 2) * sin($deltaLon / 2);
        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

        return $earthRadius * $c;
    }
}
