<?php

use app\libraries\CommonHelper;
use app\libraries\DateHelper;
use app\libraries\ICSParser;
use app\libraries\Tenants;
use app\libraries\Userstamp;

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

class Event_timeslot_model extends MY_Model
{
    use Tenants;

    protected $table;
    public $courseDate;
    public $tbl = 'event_timeslot';
    public $short = 'et';

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

        $this->load->model('Course_model');
        $this->load->model('Event_course_model');
        //        $this->table = $this->tbl.' '.$this->short;
        $this->table = $this->table_prefix . 'event_timeslot';
    }

    public function listing()
    {
        $this->tenant();

        return $this->db->from($this->table)->get()->result_array();
    }

    public function listing_first($eventId)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where('mas_event_timeslot.event_id', $eventId)
            ->select('
                id, 
                startdate, 
                startdate AS startdateTimestamp, 
                starttime,
                endtime,
                CONCAT(starttime, " - ", endtime) AS daterange
            ')
            ->get()
            ->row_array();
    }

    public function listing_by_event_id($eventId)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where('mas_event_timeslot.event_id', $eventId)
            ->select('
                id, 
                FROM_UNIXTIME(startdate, "%Y-%m-%d") AS startdate, 
                startdate AS startdateTimestamp, 
                starttime,
                endtime,
                CONCAT(starttime, " - ", endtime) AS daterange,
                holiday_skip
            ')
            ->get()
            ->result_array();
    }

    public function listing_by_event_id_lesson($eventId)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where('mas_event_timeslot.event_id', $eventId)
            ->where('mas_event_timeslot.holiday_skip IS NULL', null, false)
            ->select('
                id, 
                FROM_UNIXTIME(startdate, "%Y-%m-%d") AS startdate, 
                startdate AS startdateTimestamp, 
                starttime,
                endtime,
                CONCAT(starttime, " - ", endtime) AS daterange
            ')
            ->get()
            ->result_array();
    }

    public function listing_selected_months_day_of_weeks($eventId, $selectedMonths, $dayOfWeeks = [])
    {
        $this->tenant();

        $this->db->from($this->table)
            ->where('mas_event_timeslot.event_id', $eventId)
            ->where('mas_event_timeslot.holiday_skip IS NULL', null, false)
            ->where('FROM_UNIXTIME(startdate, "%Y-%m") IN ("' . implode('","', $selectedMonths) . '")', null, false);

        if (!empty($dayOfWeeks)) {
            $this->db->where('DAYOFWEEK(FROM_UNIXTIME(startdate)) IN (' . implode(',', $dayOfWeeks) . ')', null, false);
        }

        return $this->db->select('
            id, 
            FROM_UNIXTIME(startdate, "%Y-%m") AS selected_month, 
            FROM_UNIXTIME(startdate, "%Y-%m-%d") AS startdate, 
            startdate AS startdateTimestamp, 
            starttime,
            endtime,
            holiday_skip,
            CONCAT(starttime, " - ", endtime) AS daterange
        ')
            ->get()
            ->result_array();
    }

    public function listing_monthly($eventId, $year, $month)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where('mas_event_timeslot.event_id', $eventId)
            ->where('mas_event_timeslot.holiday_skip IS NULL', null, false)
            ->where('FROM_UNIXTIME(startdate, "%Y-%m") = "' . sprintf('%s-%s', $year, $month) . '"', null, false)
            ->select('
                id, 
                FROM_UNIXTIME(startdate, "%Y-%m") AS selected_month, 
                FROM_UNIXTIME(startdate, "%Y-%m-%d") AS startdate, 
                startdate AS startdateTimestamp, 
                starttime,
                endtime,
                CONCAT(starttime, " - ", endtime) AS daterange
            ')
            ->get()
            ->result_array();
    }

    public function listing_lumpsum($eventId)
    {
        return $this->listing_by_event_id($eventId);
    }


    public function listing_in_enrollment_selection($eventId, $startdate)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->select('
                id, 
                FROM_UNIXTIME(startdate, "%Y-%m-%d") AS startdate, 
                startdate AS startdateTimestamp, 
                CONCAT(starttime, " - ", endtime) AS daterange
            ')
            ->where('event_id', $eventId)
            ->where('startdate >=', $startdate, false)
            ->get()
            ->result_array();
    }

    public function listing_in_ids($ids)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where_in('id', $ids)
            ->order_by('startdate', 'asc')
            ->select('
                id, 
                FROM_UNIXTIME(startdate, "%Y-%m") AS selected_month, 
                FROM_UNIXTIME(startdate, "%Y-%m-%d") AS startdate, 
                startdate AS startdateTimestamp, 
                starttime,
                endtime,
                CONCAT(starttime, " - ", endtime) AS daterange
            ')
            ->get()
            ->result_array();
    }

    public function listing_event_startdate($eventId, $startdate)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where('event_id', $eventId)
            ->where('startdate >=', $startdate, false)
            ->get()
            ->result_array();
    }

    public function detail($id)
    {
        $this->tenant();

        return $this->db->from($this->table)->where('id', $id)->get()->row_array();
    }

    // protected function regular($params, $course, $timeslots = [])
    // {
    //     $edit = count($timeslots) > 0;
    //     $editFoundFirstTimeslot = false;
    //     $this->tenant();
    //     $this->courseDate = null;
    //     $hk = new DateTimeZone('Asia/Hong_Kong');
    //     $fromDate = new DateTime(sprintf('%s 00:00:00', $params['date_from']), $hk);
    //     $toDate = new DateTime(sprintf('%s 00:00:00', $params['date_to']), $hk);
    //     $selectedWeekdays = $this->getSelectedWeekdays($params);
    //     $duration = $course['duration'];
    //     $icsParser = new ICSParser(FCPATH . '/uploads/public_holiday/1576452468-tc.ics');
    //     foreach ($selectedWeekdays as $dayOfWeek => $starttime) {
    //         $cursorDate = $fromDate;
    //         $toDateTimestamp = $toDate->getTimestamp();
    //         while (true) {
    //             $cursorDateTimestamp = $cursorDate->getTimestamp();
    //             $cursorDayOfWeek = intval(date('w', $cursorDateTimestamp));
    //             list($hours, $minutes) = explode(':', $starttime);
    //             $hours = intval($hours);
    //             $minutes = intval($minutes);
    //             $startTimestamp = strtotime(sprintf('+%d hours %d minutes', $hours, $minutes), $cursorDateTimestamp);
    //             $endtime = date('H:i', strtotime(sprintf('+%d minutes', $duration), $startTimestamp));
    //             switch (true) {
    //                 case $cursorDateTimestamp > $toDateTimestamp:
    //                     break 3;
    //                 case $cursorDayOfWeek == $dayOfWeek:
    //                     if ($this->courseDate == null) {
    //                         $this->courseDate = date('Y-m-d', $cursorDateTimestamp);
    //                     }
    //                     switch (count($timeslots) > 0) {
    //                         case true:
    //                             if (!$editFoundFirstTimeslot && $edit && $cursorDate != date('Y-m-d', $timeslots[0]['startdate'])) {
    //                                 break;
    //                             }
    //                             $editFoundFirstTimeslot = true;
    //                             $item = array_shift($timeslots);
    //                             $this->db->update($this->table, Userstamp::update([
    //                                 'event_id' => $params['event_id'],
    //                                 'startdate' => $cursorDateTimestamp,
    //                                 'starttime' => $starttime,
    //                                 'endtime' => $endtime,
    //                                 'holiday_skip' => $icsParser->checkIfHoliday($cursorDateTimestamp),
    //                             ]), ['id' => $item['id']]);
    //                             break;
    //                         case false:
    //                             if ($edit && $params['apply'] == 'current') {
    //                                 break 3;
    //                             }
    //                             $this->db->insert($this->table, [
    //                                 'event_id' => $params['event_id'],
    //                                 'startdate' => $cursorDateTimestamp,
    //                                 'starttime' => $starttime,
    //                                 'endtime' => $endtime,
    //                                 'holiday_skip' => $icsParser->checkIfHoliday($cursorDateTimestamp),
    //                             ]);
    //                             break;
    //                     }
    //                     $nextDateTimestamp = strtotime('+7 days', $cursorDateTimestamp);
    //                     $cursorDate = (new DateTime('now', $hk))->setTimestamp($nextDateTimestamp);
    //                     break;
    //                 case $cursorDayOfWeek > $dayOfWeek:
    //                     $remainingDaysToNextWeek = 7 - $cursorDayOfWeek;
    //                     $diffInDayOfWeek = $remainingDaysToNextWeek + $dayOfWeek;
    //                     $nextDateTimestamp = strtotime(sprintf('+%d days', $diffInDayOfWeek), $cursorDateTimestamp);
    //                     $cursorDate = (new DateTime('now', $hk))->setTimestamp($nextDateTimestamp);
    //                     break;
    //                 case $cursorDayOfWeek < $dayOfWeek:
    //                     $diffInDayOfWeek = $dayOfWeek - $cursorDayOfWeek;
    //                     $nextDateTimestamp = strtotime(sprintf('+%d days', $diffInDayOfWeek), $cursorDateTimestamp);
    //                     $cursorDate = (new DateTime('now', $hk))->setTimestamp($nextDateTimestamp);
    //                     break;
    //             }
    //         }
    //     }
    //     // Whenever the number of record to be update is less than current timeslots, make the remaining => holiday_skip + update_skip
    //     // It becomes a holiday because of this update
    //     if (count($timeslots) > 0) {
    //         foreach ($timeslots as $item) {
    //             $this->db->update($this->table, Userstamp::update([
    //                 'holiday_skip' => 1,
    //                 'update_skip' => 1,
    //             ]), ['id' => $item['id']]);
    //         }
    //     }
    //     return;
    // }

    public function month($params, $eventId, $course)
    {
        $this->tenant();

        $course = $this->Course_model->detail($params['course_id']);
        $fromDate = $params['date_from'];
        $toDate = $params['date_to'];
        $batch = $this->listing_month_dates($course, $fromDate, $toDate, $params, $eventId);
        $res = [];
        if (!empty($batch)) {
            $this->db->insert_batch($this->table, $batch);
            foreach ($batch as $item) {
                array_push($res, [
                    'weekday' => date('w', $item['startdate']),
                    'timeslot' => date('Y-m-d', $item['startdate']) . ' ' . $item['starttime']
                ]);
            }
        }
        return $res;
    }

    public function listing_month_dates($course, $fromDate, $toDate, $params, $eventId = '')
    {

        $selectedWeekdays = $this->getSelectedWeekdays($params);

        $hk = new DateTimeZone('Asia/Hong_Kong');

        // From Date information
        $_fromDate = new DateTime(sprintf('%s-01 00:00:00', $fromDate), $hk);
        $timestamp = $_fromDate->getTimestamp();
        $endDateTimestamp = DateTime::createFromFormat('Y-m-d', $toDate, $hk)->getTimestamp();

        $dt = $timestamp;
        $w = date('w', $timestamp);

        $duration = intval($course['duration']);

        $icsParser = new ICSParser(base_url() . 'uploads/public_holiday/1576452468-tc.ics');

        $dayOfWeeks = array_keys($selectedWeekdays);
        $fw = $dayOfWeeks[0] ?? '';

        $res = [];
        //        log_message('debug','empty selectedweekdays?'.empty($selectedWeekdays));
        if (!empty($selectedWeekdays)) {
            while (true) {
                $iterator = 0;
                foreach ($selectedWeekdays as $dayOfWeek => $starttime) {
                    if ($dt > $endDateTimestamp)
                        break 2;

                    if ($w > $dayOfWeek) {

                        continue;
                    }

                    if ($w < $dayOfWeek) {
                        $diff = $dayOfWeek - $w;

                        $dt = strtotime(sprintf('+%d days', $diff), $dt);
                        $w = $dayOfWeek;

                        if ($dt > $endDateTimestamp)
                            break 2;
                    }

                    $isHoliday = $icsParser->checkIfHoliday($dt);


                    $st = DateTime::createFromFormat('Y-m-d H:i', sprintf('%s %s', date('Y-m-d', $dt), $starttime))->getTimestamp();
                    $et = strtotime(sprintf('+%s minutes', $duration), $st);
                    if ($isHoliday == null) {
                        array_push($res, [
                            'event_id' => $eventId,
                            'startdate' => $dt,
                            'starttime' => $starttime,
                            'endtime' => date('H:i', $et),
                            'holiday_skip' => $isHoliday,
                        ]);
                    }

                    if (!$isHoliday)
                        $iterator++;
                }

                // Jump to next week
                $nwDiff = 7 - $w;
                if ($nwDiff != 0) {
                    $dt = strtotime(sprintf('+%d days', $nwDiff), $dt);
                    $w = date('w', $dt);
                }

                // match $fw
                if (empty($fw)) {
                    $w = date('w', time());
                } else {
                    $fwDiff = $fw - $w;
                    $dt = strtotime(sprintf('+%d days', $fwDiff), $dt);
                    $w = date('w', $dt);
                }
            }

            //$this->courseDate = date('Y-m-d', !empty($res[0]) ? $res[0]['startdate'] : time());
            $this->courseDate = empty($res[0]) ? $res[0]['startdate'] : date('Y-m-d', time());
        }
        //exit;
        return $res;
    }

    public function lesson($params, $eventId, $course, $timeslots = [])
    {
        $this->tenant();

        $course = $this->Course_model->detail($params['course_id']);
        $fromDate = $params['date_from'];
        $totalLessons = $params['total_lessons'];
        $batch = $this->listing_lesson_dates($course, $fromDate, $totalLessons, $params, $eventId);
        $this->db->insert_batch($this->table, $batch);

        $res = [];

        foreach ($batch as $item) {
            array_push($res, [
                'weekday' => date('w', $item['startdate']),
                'timeslot' => date('Y-m-d', $item['startdate']) . ' ' . $item['starttime']
            ]);
        }

        return $res;
    }

    public function listing_lesson_dates($course, $fromDate, $totalLessons, $params, $eventId = '')
    {
        $selectedWeekdays = $this->getSelectedWeekdays($params);
        $hk = new DateTimeZone('Asia/Hong_Kong');

        $totalLessons = intval($totalLessons);

        // Setting center information
        $this->load->model('Setting_center_model');
        $settings = $this->Setting_center_model->detail();

        // From Date information
        $_fromDate = new DateTime(sprintf('%s 00:00:00', $fromDate), $hk);
        $timestamp = $_fromDate->getTimestamp();
        $endDateTimestamp = $totalLessons == 0 ? DateTime::createFromFormat('Y-m-d', $settings['default_event_end_date'], $hk)->getTimestamp() : null;

        $dt = $timestamp;
        $w = date('w', $timestamp);

        $fw = null;
        $duration = intval($course['duration']);
        $icsParser = new ICSParser(base_url() . '/uploads/public_holiday/1576452468-tc.ics');

        $dayOfWeeks = array_keys($selectedWeekdays);
        $fw = $dayOfWeeks[0];

        $res = [];
        $iterator = 0;

        while (true) {
            foreach ($selectedWeekdays as $dayOfWeek => $starttime) {
                if ($endDateTimestamp) {
                    if ($dt > $endDateTimestamp)
                        break 2;
                } else if ($iterator == $totalLessons)
                    break 2;

                if ($w > $dayOfWeek) {
                    continue;
                }

                if ($w < $dayOfWeek) {
                    $diff = $dayOfWeek - $w;

                    $dt = strtotime(sprintf('+%d days', $diff), $dt);
                    $w = $dayOfWeek;
                }

                $isHoliday = $icsParser->checkIfHoliday($dt);

                $st = DateTime::createFromFormat('Y-m-d H:i', sprintf('%s %s', date('Y-m-d', $dt), $starttime))->getTimestamp();
                $et = strtotime(sprintf('+%s minutes', $duration), $st);

                array_push($res, [
                    'event_id' => $eventId,
                    'startdate' => $dt,
                    'starttime' => $starttime,
                    'endtime' => date('H:i', $et),
                    'holiday_skip' => $isHoliday,
                ]);

                if (!$isHoliday)
                    $iterator++;
            }

            // Jump to next week
            $nwDiff = 7 - $w;
            if ($nwDiff != 0) {
                $dt = strtotime(sprintf('+%d days', $nwDiff), $dt);
                $w = date('w', $dt);
            }

            // match $fw
            $fwDiff = $fw - $w;
            $dt = strtotime(sprintf('+%d days', $fwDiff), $dt);
            $w = date('w', $dt);
        }

        $this->courseDate = date('Y-m-d', $res[0]['startdate']);
        return $res;
    }

    public function period($params, $eventId, $course, $timeslots = [])
    {
        $this->tenant();

        $res = [];

        $edit = count($timeslots) > 0;
        $editFoundFirstTimeslot = false;

        $this->courseDate = null;

        $_items = $params['L'];

        $duration = $course['duration'];

        foreach ($_items as $_item) {
            $startdate = $_item['date'];
            $starttime = $_item['time'];
            if ($startdate == "" && $starttime == "") {
                continue;
            }

            $datetime = sprintf('%s %s', $startdate, $starttime);

            // * $datetime = $cursorDate
            $cursorDate = DateTime::createFromFormat('Y-m-d H:i', $datetime, new DateTimeZone('Asia/Hong_Kong'));
            $cursorDateTimestamp = $cursorDate->getTimestamp();
            $courseDate = DateTime::createFromFormat('Y-m-d', $datetime, new DateTimeZone('Asia/Hong_Kong'));
            $courseDateTimestamp = $cursorDate->getTimestamp();


            $starttime = $starttime;
            $endtime = date('H:i', strtotime(sprintf('+%d minutes', $duration), $cursorDateTimestamp));

            if ($this->courseDate == null) {
                $this->courseDate = $courseDate;
            }

            switch (count($timeslots) > 0) {
                case true:
                    if (!$editFoundFirstTimeslot && $edit && $courseDate != date('Y-m-d', $timeslots[0]['startdate'])) {
                        break;
                    }
                    $editFoundFirstTimeslot = true;
                    $item = array_shift($timeslots);
                    $this->db->update($this->table, Userstamp::update([
                        'event_id' => $eventId,
                        'startdate' => $courseDateTimestamp,
                        'starttime' => $starttime,
                        'endtime' => $endtime,
                        'holiday_skip' => null
                    ]), ['id' => $item['id']]);
                    break;

                case false:
                    $this->db->insert($this->table, Userstamp::create([
                        'event_id' => $eventId,
                        'startdate' => $courseDateTimestamp,
                        'starttime' => $starttime,
                        'endtime' => $endtime,
                        'holiday_skip' => null
                    ]));
                    break;
            }

            array_push($res, [
                'weekday' => date('w', $cursorDateTimestamp),
                'timeslot' => $datetime
            ]);
        }

        // Whenever the number of record to be update is less than current timeslots, make the remaining => holiday_skip + update_skip
        // It becomes a holiday because of this update
        if (count($timeslots) > 0) {
            foreach ($timeslots as $item) {
                $this->db->update($this->table, Userstamp::update([
                    'holiday_skip' => 1,
                    'update_skip' => 1,
                ]), ['id' => $item['id']]);
            }
        }

        $this->courseDate = explode(' ', $res[0]['timeslot'])[0];
        return $res;
    }

    // public function update($params, $id)
    // {
    //     $item = $this->detail($id);
    //     $eventId = $params['event_id'];
    //     $courseId = $this->Event_course_model->detail_eventId($eventId)['course_id'];
    //     $course = $this->Course_model->detail($courseId);
    //     $hasHolidaySkip = $this->Course_model->isRegular($course['mode']);
    //     switch ($params['apply']) {
    //         case 'current':
    //             $timeslots = [$item];
    //             break;
    //         case 'future':
    //             $timeslots = $this->listing_event_startdate($eventId, $item['startdate']);
    //             break;
    //     }
    //     switch ($hasHolidaySkip) {
    //         case true:
    //             $this->regular($params, $course, $timeslots);
    //             break;
    //         case false:
    //             $this->nonRegular($params, $course, $timeslots);
    //             break;
    //     }
    // }

    public function delete_event_startdate($eventId, $startdate)
    {
        $this->tenant();

        // switch ($params['apply_delete']) {
        //     case 'current':
        //         $timeslots = [$item];
        //         break;
        //     case 'future':
        //         $timeslots = $this->listing_event_startdate($eventId, $item['startdate']);
        //         break;
        // }

        $this->db
            ->where('event_id', $eventId)
            ->where('startdate >=', $startdate, false);

        return $this->db->delete($this->table);
    }

    public function getSelectedWeekdays($params)
    {
        $weekdays = DateHelper::getDefaultWeektimes();
        $selectedWeekdays = [];

        foreach ($weekdays as $index => $weeday) {
            if (!empty($params[$weeday])) {
                $selectedWeekdays[$index] = $params[$weeday];
            }
        }

        return $selectedWeekdays;
    }

    public function delete_by_event_id($eventId)
    {
        $this->tenant();

        $this->db->delete($this->table, ['event_id' => $eventId]);
    }

    public function detail_selected_date($selectedDate)
    {
        $this->tenant();

        return $this->db->from($this->table)
            ->where('FROM_UNIXTIME(mas_event_timeslot.startdate, "%Y-%m-%d") = "' . $selectedDate . '"', null, false)
            ->where('holiday_skip IS NULL', null, false)
            ->get()
            ->result_array();
    }


    public function new_period($params, $eventId, $course)
    {
        $this->tenant();

        // $course = $this->Course_model->detail($params['course_id']);
        $fromDate = $params['date_from'];
        $toDate = $params['date_to'];
        if (isset($params['selected_timeslot'])) {

            $batch = $this->add_end_time_selected_timeslot($course, $params, $eventId);
        } else {
            $batch = $this->listing_month_dates($course, $fromDate, $toDate, $params, $eventId);
        }
        $res = [];
        if (!empty($batch)) {
            $this->db->insert_batch($this->table, $batch);
            foreach ($batch as $item) {
               
                if ($item['holiday_skip'] == "") {
                    array_push($res, [
                        'weekday' => date('w', $item['startdate']),
                        'timeslot' => date('Y-m-d', $item['startdate']) . ' ' . $item['starttime']
                    ]);
                }
            }
            
        }
        return $res;
    }


    public function add_end_time_selected_timeslot($course, $params, $eventId)
    {

        $res = [];
        $duration = intval($course['duration']);
        $selected_timeslot = $params['selected_timeslot'];
        foreach ($selected_timeslot as $timeslot) {

            $timeslot_information = explode('|', $timeslot);

            $st = DateTime::createFromFormat('d-m-Y H:i', sprintf('%s %s', $timeslot_information[0], $timeslot_information[1]))->getTimestamp();
            $et = strtotime(sprintf('+%s minutes', $duration), $st);
            array_push($res, [
                "event_id" => $eventId,
                'startdate' => $st,
                'starttime' => $timeslot_information[1],
                "endtime" =>  date('H:i', $et),
                'holiday_skip' => null,
            ]);
        }
        return $res;
    }

    public function get_id($id)
    {
        return $this->db->from("mas_event_timeslot")
            ->select("*")
            ->where('id', $id)
            ->get()
            ->row_array();
    }
}
