<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Scheduler extends CI_Controller {

    public function __construct()
    {
        parent::__construct();

        $this->load->database();

        date_default_timezone_set('Asia/Jakarta');
    }

    // =====================================================
    // PROCESS ATTENDANCE LOG
    // =====================================================
    public function process_attendance()
    {
        echo "PROCESS ATTENDANCE START\n";
    
        // =============================================
        // GET PENDING LOG
        // =============================================
        $logs = $this->db
            ->where('process_status','pending')
            ->order_by('check_time','ASC')
            ->limit(1000)
            ->get('k_attendance_logs')
            ->result();
    
        foreach($logs as $log){
    
            try{
    
                // =====================================
                // GET EMPLOYEE
                // =====================================
                $employee = $this->db
                    ->where(
                        'fingerprint_user_id',
                        $log->user_id
                    )
                    ->where('is_active',1)
                    ->get('k_employees')
                    ->row();
    
                if(!$employee){
    
                    $this->updateLogStatus(
                        $log->id,
                        'failed'
                    );
    
                    echo "FAILED EMPLOYEE : {$log->user_id}\n";
    
                    continue;
                }
    
                // =====================================
                // UPDATE EMPLOYEE ID
                // =====================================
                $this->db
                    ->where('id',$log->id)
                    ->update(
                        'k_attendance_logs',
                        [
                            'employee_id' => $employee->id
                        ]
                    );
    
                $logDateTime = date(
                    'Y-m-d H:i:s',
                    strtotime($log->check_time)
                );
    
                // =====================================
                // FIND SCHEDULE
                // SUPPORT SHIFT MALAM
                // =====================================
                $this->db->from(
                    'k_employee_shift_schedules'
                );
    
                $this->db->where(
                    'employee_id',
                    $employee->id
                );
    
                $this->db->where(
                    'status',
                    'published'
                );
    
                // =====================================
                // RANGE SHIFT
                // =====================================
                $this->db->where("
                    '{$logDateTime}' BETWEEN
                    DATE_SUB(start_datetime, INTERVAL 3 HOUR)
                    AND
                    DATE_ADD(end_datetime, INTERVAL 6 HOUR)
                ", null, false);
    
                $this->db->order_by(
                    'start_datetime',
                    'DESC'
                );
    
                $schedule = $this->db->get()->row();
    
                // =====================================
                // SCHEDULE NOT FOUND
                // =====================================
                if(!$schedule){
    
                    $this->updateLogStatus(
                        $log->id,
                        'failed'
                    );
    
                    echo "FAILED SCHEDULE : {$logDateTime}\n";
    
                    continue;
                }
    
                // =====================================
                // GET SHIFT
                // =====================================
                $shift = $this->db
                    ->where('id',$schedule->shift_id)
                    ->get('k_shifts')
                    ->row();
    
                if(!$shift){
    
                    $this->updateLogStatus(
                        $log->id,
                        'failed'
                    );
    
                    echo "FAILED SHIFT : {$schedule->shift_id}\n";
    
                    continue;
                }
    
                // =====================================
                // ATTENDANCE DATE
                // =====================================
                $attendance_date = date(
                    'Y-m-d',
                    strtotime($schedule->start_datetime)
                );
    
                // =====================================
                // GET ATTENDANCE
                // =====================================
                $attendance = $this->db
                    ->where(
                        'employee_id',
                        $employee->id
                    )
                    ->where(
                        'attendance_date',
                        $attendance_date
                    )
                    ->get('k_attendances')
                    ->row();
    
                // =====================================
                // CHECK LATE
                // =====================================
                $late_minutes = 0;
    
                $maxCheckin = strtotime(
                    $schedule->start_datetime
                ) + (
                    $shift->late_tolerance_minutes * 60
                );
    
                if(
                    strtotime($logDateTime)
                    >
                    $maxCheckin
                ){
    
                    $late_minutes = floor(
                        (
                            strtotime($logDateTime)
                            -
                            strtotime($schedule->start_datetime)
                        ) / 60
                    );
    
                    if($late_minutes < 0){
                        $late_minutes = 0;
                    }
                }
    
                // =====================================
                // INSERT CHECKIN
                // =====================================
                if(!$attendance){
    
                    $this->db->insert(
                        'k_attendances',
                        [
    
                            'employee_id'          => $employee->id,
    
                            'attendance_date'      => $attendance_date,
    
                            'checkin_time'         => $logDateTime,
    
                            'late_minutes'         => $late_minutes,
    
                            'attendance_status'    => (
                                $late_minutes > 0
                                ? 'late'
                                : 'present'
                            ),
    
                            'shift_id'             => $shift->id,
    
                            'attendance_log_in_id' => $log->id,
    
                            'created_at'           => date('Y-m-d H:i:s')
                        ]
                    );
    
                    echo "CHECKIN : {$employee->full_name}\n";
    
                } else {
    
                    // =================================
                    // SUDAH ADA CHECKOUT
                    // =================================
                    if(!empty($attendance->checkout_time)){
    
                        $this->updateLogStatus(
                            $log->id,
                            'processed'
                        );
    
                        echo "SKIP LOG (SUDAH CHECKOUT)\n";
    
                        continue;
                    }
    
                    // =================================
                    // CEK SELISIH JAM
                    // =================================
                    $diffMinutes = floor(
                        (
                            strtotime($logDateTime)
                            -
                            strtotime($attendance->checkin_time)
                        ) / 60
                    );
    
                    // =================================
                    // MINIMAL 2 JAM
                    // BARU DIANGGAP CHECKOUT
                    // =================================
                    if($diffMinutes < 120){
    
                        $this->updateLogStatus(
                            $log->id,
                            'processed'
                        );
    
                        echo "SKIP DUPLICATE LOG : {$employee->full_name}\n";
    
                        continue;
                    }
    
                    // =================================
                    // WORK HOURS
                    // =================================
                    $workHours = (
                        strtotime($logDateTime)
                        -
                        strtotime($attendance->checkin_time)
                    ) / 3600;
    
                    if($workHours < 0){
                        $workHours = 0;
                    }
    
                    // =================================
                    // EARLY LEAVE
                    // =================================
                    $early_leave_minutes = 0;
    
                    if(
                        strtotime($logDateTime)
                        <
                        strtotime($schedule->end_datetime)
                    ){
    
                        $early_leave_minutes = floor(
                            (
                                strtotime($schedule->end_datetime)
                                -
                                strtotime($logDateTime)
                            ) / 60
                        );
    
                        if($early_leave_minutes < 0){
                            $early_leave_minutes = 0;
                        }
                    }
    
                    // =================================
                    // OVERTIME
                    // =================================
                    $overtime_hours = 0;
    
                    if(
                        strtotime($logDateTime)
                        >
                        strtotime($schedule->end_datetime)
                    ){
    
                        $overtime_hours = round(
                            (
                                strtotime($logDateTime)
                                -
                                strtotime($schedule->end_datetime)
                            ) / 3600,
                            2
                        );
    
                        if($overtime_hours < 0){
                            $overtime_hours = 0;
                        }
                    }
    
                    // =================================
                    // UPDATE CHECKOUT
                    // =================================
                    $this->db
                        ->where(
                            'id',
                            $attendance->id
                        )
                        ->update(
                            'k_attendances',
                            [
    
                                'checkout_time'         => $logDateTime,
    
                                'attendance_log_out_id' => $log->id,
    
                                'work_hours'            => round($workHours,2),
    
                                'early_leave_minutes'   => $early_leave_minutes,
    
                                'overtime_hours'        => $overtime_hours
                            ]
                        );
    
                    echo "CHECKOUT : {$employee->full_name}\n";
                }
    
                // =====================================
                // UPDATE LOG STATUS
                // =====================================
                $this->updateLogStatus(
                    $log->id,
                    'processed'
                );
    
                echo "SUCCESS LOG ID : {$log->id}\n";
    
            } catch(Exception $e){
    
                $this->updateLogStatus(
                    $log->id,
                    'failed'
                );
    
                echo "ERROR : " . $e->getMessage() . "\n";
            }
        }
    
        echo "PROCESS ATTENDANCE DONE\n";
    }
    
    // =====================================================
    // AUTO CLOSE ATTENDANCE
    // =====================================================
    public function auto_close_attendance()
    {
        echo "AUTO CLOSE START\n";
    
        // =============================================
        // AMBIL ATTENDANCE BELUM CHECKOUT
        // =============================================
        $attendances = $this->db
            ->where('checkout_time IS NULL', null, false)
            ->get('k_attendances')
            ->result();
    
        foreach($attendances as $attendance){
    
            // =========================================
            // GET SCHEDULE
            // =========================================
            $schedule = $this->db
                ->where(
                    'employee_id',
                    $attendance->employee_id
                )
                ->where(
                    'shift_id',
                    $attendance->shift_id
                )
                ->where(
                    'DATE(start_datetime)',
                    $attendance->attendance_date
                )
                ->get('k_employee_shift_schedules')
                ->row();
    
            if(!$schedule){
                continue;
            }
    
            // =========================================
            // AUTO CLOSE
            // END SHIFT + 4 JAM
            // =========================================
            $autoCloseTime = date(
                'Y-m-d H:i:s',
                strtotime(
                    $schedule->end_datetime . ' +4 hours'
                )
            );
    
            // =========================================
            // BELUM WAKTUNYA
            // =========================================
            if(
                strtotime(date('Y-m-d H:i:s'))
                <
                strtotime($autoCloseTime)
            ){
                continue;
            }
    
            // =========================================
            // WORK HOURS
            // =========================================
            $workHours = (
                strtotime($schedule->end_datetime)
                -
                strtotime($attendance->checkin_time)
            ) / 3600;
    
            if($workHours < 0){
                $workHours = 0;
            }
    
            // =========================================
            // AUTO CHECKOUT
            // =========================================
            $this->db
                ->where('id',$attendance->id)
                ->update(
                    'k_attendances',
                    [
    
                        'checkout_time' => $schedule->end_datetime,
    
                        'work_hours'    => round($workHours,2),
    
                        'notes'         => 'Auto checkout by system'
                    ]
                );
    
            echo "AUTO CLOSE EMPLOYEE : {$attendance->employee_id}\n";
        }
    
        echo "AUTO CLOSE DONE\n";
    }

    // =====================================================
    // GENERATE DAILY ATTENDANCE
    // =====================================================
    public function generate_daily_attendance()
    {
        echo "GENERATE DAILY START\n";

        // =============================================
        // GENERATE HARI KEMARIN
        // =============================================
        $date = date(
            'Y-m-d',
            strtotime('-1 day')
        );

        // =============================================
        // GET ALL SCHEDULE
        // =============================================
        $schedules = $this->db
            ->where('schedule_date', $date)
            ->where('status','published')
            ->get('k_employee_shift_schedules')
            ->result();

        foreach($schedules as $schedule){

            // =========================================
            // CHECK ATTENDANCE EXIST
            // =========================================
            $attendance = $this->db
                ->where(
                    'employee_id',
                    $schedule->employee_id
                )
                ->where(
                    'attendance_date',
                    $date
                )
                ->get('k_attendances')
                ->row();

            if($attendance){
                continue;
            }

            // =========================================
            // CHECK HOLIDAY
            // =========================================
            $holiday = $this->db
                ->where('holiday_date',$date)
                ->get('k_holidays')
                ->row();

            if($holiday){

                $this->db->insert(
                    'k_attendances',
                    [

                        'employee_id'       => $schedule->employee_id,

                        'attendance_date'   => $date,

                        'attendance_status' => 'holiday',

                        'is_holiday'        => 1,

                        'shift_id'          => $schedule->shift_id,

                        'notes'             => $holiday->holiday_name
                    ]
                );

                continue;
            }

            // =========================================
            // CHECK LEAVE
            // =========================================
            $leave = $this->db
                ->where(
                    'employee_id',
                    $schedule->employee_id
                )
                ->where(
                    'approval_status',
                    'approved'
                )
                ->where('start_date <=',$date)
                ->where('end_date >=',$date)
                ->get('k_leave_requests')
                ->row();

            if($leave){

                $this->db->insert(
                    'k_attendances',
                    [

                        'employee_id'       => $schedule->employee_id,

                        'attendance_date'   => $date,

                        'attendance_status' => $leave->leave_type,

                        'shift_id'          => $schedule->shift_id,

                        'notes'             => $leave->reason
                    ]
                );

                continue;
            }

            // =========================================
            // DEFAULT ALPHA
            // =========================================
            $this->db->insert(
                'k_attendances',
                [

                    'employee_id'       => $schedule->employee_id,

                    'attendance_date'   => $date,

                    'attendance_status' => 'alpha',

                    'shift_id'          => $schedule->shift_id,

                    'notes'             => 'Tidak hadir'
                ]
            );

            echo "GENERATE EMPLOYEE : {$schedule->employee_id}\n";
        }

        echo "GENERATE DAILY DONE\n";
    }

    // =====================================================
    // UPDATE LOG STATUS
    // =====================================================
    private function updateLogStatus(
        $id,
        $status
    ){

        $this->db
            ->where('id',$id)
            ->update(
                'k_attendance_logs',
                [
                    'process_status' => $status
                ]
            );
    }
}