<?php

namespace Database\Seeders;

use App\Models\Attendance;
use App\Models\User;
use App\Models\Office;
use Carbon\Carbon;
use Illuminate\Database\Seeder;

class AttendanceDemoSeeder extends Seeder
{
    /**
     * Run the database seeds.
     * Generate varied attendance data for all users for the current month.
     */
    public function run(): void
    {
        $users = User::where('approval_status', 'approved')->get();
        $offices = Office::all();

        if ($users->isEmpty()) {
            $this->command->warn('No approved users found. Please create users first.');
            return;
        }

        $defaultOffice = $offices->first();
        $today = Carbon::today();
        $startOfMonth = $today->copy()->startOfMonth();

        // Status types with weights for randomization
        $statusTypes = [
            'present' => 50,      // 50% chance
            'late' => 20,         // 20% chance
            'early_leave' => 5,   // 5% chance
            'sick' => 8,          // 8% chance
            'permission' => 7,    // 7% chance
            'leave' => 5,         // 5% chance
            'absent' => 5,        // 5% chance
        ];

        $attendanceTypes = [
            'office' => 70,       // 70% chance
            'wfh' => 25,          // 25% chance
            'business_trip' => 5, // 5% chance
        ];

        $this->command->info("Generating attendance data for {$users->count()} users...");

        foreach ($users as $user) {
            $this->command->info("Processing user: {$user->name}");

            // Generate attendance for each working day from start of month to today
            $currentDate = $startOfMonth->copy();

            while ($currentDate->lte($today)) {
                // Skip weekends
                if ($currentDate->isWeekend()) {
                    $currentDate->addDay();
                    continue;
                }

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

                if ($existingAttendance) {
                    $currentDate->addDay();
                    continue;
                }

                // Randomly select status and type
                $status = $this->weightedRandom($statusTypes);
                $type = $this->weightedRandom($attendanceTypes);

                // Generate attendance based on status
                $this->createAttendance($user, $currentDate, $status, $type, $defaultOffice);

                $currentDate->addDay();
            }
        }

        $this->command->info('Attendance demo data generated successfully!');
    }

    /**
     * Create attendance record based on status type
     */
    private function createAttendance($user, Carbon $date, string $status, string $type, $office): void
    {
        $baseCheckIn = Carbon::parse($date->format('Y-m-d') . ' 08:00:00');
        $baseCheckOut = Carbon::parse($date->format('Y-m-d') . ' 17:00:00');

        $data = [
            'user_id' => $user->id,
            'company_id' => $user->company_id,
            'office_id' => $office?->id,
            'date' => $date->format('Y-m-d'),
            'type' => $type,
            'status' => $status,
        ];

        switch ($status) {
            case 'present':
                // Normal attendance: 07:45 - 08:15 check in, 17:00 - 18:00 check out
                $checkIn = $baseCheckIn->copy()->subMinutes(rand(0, 15))->addMinutes(rand(0, 15));
                $checkOut = $baseCheckOut->copy()->addMinutes(rand(0, 60));

                $data = array_merge($data, [
                    'check_in_time' => $checkIn,
                    'check_out_time' => $checkOut,
                    'check_in_latitude' => $this->randomLat(),
                    'check_in_longitude' => $this->randomLng(),
                    'check_in_distance' => rand(5, 100),
                    'check_in_address' => $this->randomAddress(),
                    'check_out_latitude' => $this->randomLat(),
                    'check_out_longitude' => $this->randomLng(),
                    'check_out_distance' => rand(5, 100),
                    'check_out_address' => $this->randomAddress(),
                    'work_duration' => $checkOut->diffInMinutes($checkIn),
                ]);
                break;

            case 'late':
                // Late: 08:30 - 10:00 check in
                $checkIn = $baseCheckIn->copy()->addMinutes(rand(30, 120));
                $checkOut = $baseCheckOut->copy()->addMinutes(rand(0, 30));

                $data = array_merge($data, [
                    'check_in_time' => $checkIn,
                    'check_out_time' => $checkOut,
                    'check_in_latitude' => $this->randomLat(),
                    'check_in_longitude' => $this->randomLng(),
                    'check_in_distance' => rand(5, 100),
                    'check_in_address' => $this->randomAddress(),
                    'check_in_notes' => $this->randomLateReason(),
                    'check_out_latitude' => $this->randomLat(),
                    'check_out_longitude' => $this->randomLng(),
                    'check_out_distance' => rand(5, 100),
                    'check_out_address' => $this->randomAddress(),
                    'work_duration' => $checkOut->diffInMinutes($checkIn),
                ]);
                break;

            case 'early_leave':
                // Early leave: normal check in, early check out (14:00 - 16:00)
                $checkIn = $baseCheckIn->copy()->subMinutes(rand(0, 15))->addMinutes(rand(0, 15));
                $checkOut = Carbon::parse($date->format('Y-m-d') . ' 14:00:00')->addMinutes(rand(0, 120));

                $data = array_merge($data, [
                    'check_in_time' => $checkIn,
                    'check_out_time' => $checkOut,
                    'check_in_latitude' => $this->randomLat(),
                    'check_in_longitude' => $this->randomLng(),
                    'check_in_distance' => rand(5, 100),
                    'check_in_address' => $this->randomAddress(),
                    'check_out_latitude' => $this->randomLat(),
                    'check_out_longitude' => $this->randomLng(),
                    'check_out_distance' => rand(5, 100),
                    'check_out_address' => $this->randomAddress(),
                    'check_out_notes' => $this->randomEarlyLeaveReason(),
                    'work_duration' => $checkOut->diffInMinutes($checkIn),
                ]);
                break;

            case 'sick':
                // Sick leave: no check in/out, type stays office
                $data['type'] = 'office';
                $data['check_in_notes'] = 'Sakit: ' . $this->randomSickReason();
                break;

            case 'permission':
                // Permission: no check in/out, type stays office
                $data['type'] = 'office';
                $data['check_in_notes'] = 'Izin: ' . $this->randomPermissionReason();
                break;

            case 'leave':
                // Annual leave: no check in/out, type stays office
                $data['type'] = 'office';
                $data['check_in_notes'] = 'Cuti tahunan';
                break;

            case 'absent':
                // Absent without notice, type stays office
                $data['type'] = 'office';
                $data['check_in_notes'] = 'Tidak hadir tanpa keterangan';
                break;

            case 'incomplete':
                // Checked in but no checkout (only for today)
                $checkIn = $baseCheckIn->copy()->subMinutes(rand(0, 15))->addMinutes(rand(0, 15));

                $data = array_merge($data, [
                    'check_in_time' => $checkIn,
                    'check_in_latitude' => $this->randomLat(),
                    'check_in_longitude' => $this->randomLng(),
                    'check_in_distance' => rand(5, 100),
                    'check_in_address' => $this->randomAddress(),
                ]);
                break;
        }

        Attendance::create($data);
    }

    /**
     * Weighted random selection
     */
    private function weightedRandom(array $weights): string
    {
        $total = array_sum($weights);
        $random = rand(1, $total);
        $current = 0;

        foreach ($weights as $item => $weight) {
            $current += $weight;
            if ($random <= $current) {
                return $item;
            }
        }

        return array_key_first($weights);
    }

    /**
     * Random latitude around Jakarta area
     */
    private function randomLat(): float
    {
        return -6.2 + (rand(-100, 100) / 10000);
    }

    /**
     * Random longitude around Jakarta area
     */
    private function randomLng(): float
    {
        return 106.8 + (rand(-100, 100) / 10000);
    }

    /**
     * Random address
     */
    private function randomAddress(): string
    {
        $addresses = [
            'Jl. Sudirman No. 123, Jakarta Pusat',
            'Jl. Thamrin No. 45, Jakarta Pusat',
            'Jl. Gatot Subroto No. 78, Jakarta Selatan',
            'Jl. HR Rasuna Said No. 12, Jakarta Selatan',
            'Jl. TB Simatupang No. 89, Jakarta Selatan',
            'Jl. Kuningan No. 34, Jakarta Selatan',
            'Jl. Mega Kuningan No. 56, Jakarta Selatan',
            'Jl. Casablanca No. 67, Jakarta Selatan',
        ];

        return $addresses[array_rand($addresses)];
    }

    /**
     * Random late reason
     */
    private function randomLateReason(): string
    {
        $reasons = [
            'Macet di jalan',
            'Ban motor bocor',
            'Hujan deras',
            'Ada kecelakaan di jalan',
            'Mengantar anak sekolah',
            'Kendala transportasi umum',
        ];

        return $reasons[array_rand($reasons)];
    }

    /**
     * Random early leave reason
     */
    private function randomEarlyLeaveReason(): string
    {
        $reasons = [
            'Urusan keluarga',
            'Janji dokter',
            'Keperluan mendesak',
            'Menjemput anak sekolah',
            'Ada acara keluarga',
        ];

        return $reasons[array_rand($reasons)];
    }

    /**
     * Random sick reason
     */
    private function randomSickReason(): string
    {
        $reasons = [
            'Demam',
            'Flu',
            'Sakit kepala',
            'Sakit perut',
            'Migrain',
            'Masuk angin',
            'Batuk pilek',
        ];

        return $reasons[array_rand($reasons)];
    }

    /**
     * Random permission reason
     */
    private function randomPermissionReason(): string
    {
        $reasons = [
            'Mengurus dokumen penting',
            'Keperluan bank',
            'Mengantar orang tua ke rumah sakit',
            'Menghadiri acara keluarga',
            'Mengurus perpanjangan SIM',
            'Rapat wali murid',
        ];

        return $reasons[array_rand($reasons)];
    }
}
