<?php

namespace App\Controllers;

use App\Models\GuestModel;
use App\Models\SessionModel;
use App\Models\CheckinModel;
use App\Models\GroupModel;
use Dompdf\Dompdf;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;

class Plans extends BaseController
{

    private $guestmodel, $sessionmodel, $checkinmodel, $groupmodel;

    function __construct() {
        parent::__construct();
        $this->guestmodel = new GuestModel();
        $this->groupmodel = new GroupModel();
        $this->sessionmodel = new SessionModel();
        $this->checkinmodel = new CheckinModel();
        helper('functions');
    }

    protected function generate_arrays($type, $session_id) {
        $checkin = $this->checkinmodel->select('guest_id')->where(['session_id' => $session_id, 'status' => 1])->get()->getResultArray();
        $checkin = array_column($checkin, 'guest_id');
        
        $guests = array();
        if(!empty($checkin))
            $guests = $this->guestmodel->find($checkin); 
        $booked = array();
        $guests = array_combine(array_column($guests, 'id'), $guests);
        $groups = $this->groupmodel->findAll();
        $groups = array_combine(array_column($groups, 'id'), $groups);
        $plan_model = null;
        if($type == "seating") 
            $plan_model = &$this->seatingmodel;
        else 
            $plan_model = &$this->stagemodel;

        $seats = $plan_model->where('session_id', $session_id)->get()->getResultArray();
        $error = array();
        foreach($seats as $seat) {
            if($seat['group_id'] == null) {
                if(!isset($guests[$seat['guest_id']])) {
                    $error[] = $seat['guest_id'];       
                    continue;
                    // echo "<pre>"; print_r($seat); print_r($guests[$seat['guest_id']]); echo "</pre>"; exit;
                }
                $guest = &$guests[$seat['guest_id']];
                $booked[$seat[$type]]['id'] = $guests[$seat['guest_id']]['id'];
                // $booked[$seat[$type]]['name'] = $guest['title'] . " " . $guest['name'] . " " . $guest['surname'] . " " . $guest['designation'];
                $booked[$seat[$type]]['name'] = $guest['title'] . " " . $guest['name'] . " " . $guest['surname'];
                $booked[$seat[$type]]['country'] = $guests[$seat['guest_id']]['country'];
                $booked[$seat[$type]]['profile_image'] = $guests[$seat['guest_id']]['profile_image'];
                $booked[$seat[$type]]['color'] = "";
                $booked[$seat[$type]]['type'] = 'guest';
                $booked[$seat[$type]]['category'] = ($guests[$seat['guest_id']]['category']?($guests[$seat['guest_id']]['category']):(''));
            } else {
                $booked[$seat[$type]]['id'] = $groups[$seat['group_id']]['id'];
                $booked[$seat[$type]]['name'] = $groups[$seat['group_id']]['title'];
                $booked[$seat[$type]]['country'] = "";
                $booked[$seat[$type]]['profile_image'] = "";
                $booked[$seat[$type]]['color'] = $groups[$seat['group_id']]['color'];
                $booked[$seat[$type]]['type'] = 'group';
                $booked[$seat[$type]]['category'] = '';
            }
            $booked[$seat[$type]][$type] = $seat[$type];
        }

        $data['groups'] = $groups;
        $data['guests'] = $guests;
        $data['booked'] = $booked;


        return $data;
    }
    
    public function plan_list($type, $session_id)
    {
        $this->data['title'] = $type . " - List";
        $this->data['template'] = "plans/plan-list";
        $this->data['css_file'] = "session.css";

        $this->data['session_id'] = $session_id;
        $this->data['type'] = $type;
        
        $this->data['flagged_tables'] = flagged_tables($session_id);

 
        if($type == 'seating'):

            $list = $this->seatingmodel->select('seating.*, session_checkin.checked_in')
                            ->where('seating.session_id', $session_id)
                            ->join('session_checkin', 'seating.guest_id = session_checkin.guest_id AND seating.session_id = session_checkin.session_id', 'left')
                            ->findAll();

        else:
            $list = $this->stagemodel->where('session_id', $session_id)->findAll();
        endif;
        $guests = array();

            $ids = array_filter(array_column($list, 'guest_id')); 
            $group_ids = array_filter(array_column($list, 'group_id'));
            $guests = array();
            $guests_unassigned = array();
            $groups = array();
            $checkin = array();

            if(count($ids) > 0) {
                $guests = $this->guestmodel->whereIn('id', $ids)->findAll();
                $guests = array_combine(array_column($guests, 'id'), $guests);
                
                $guests_unassigned = $this->guestmodel->whereNotIn('id', $ids)->findAll();
                $guests_unassigned = array_combine(array_column($guests_unassigned, 'id'), $guests_unassigned);

                $checkin = $this->checkinmodel->select('*')->where(['session_id' => $session_id, 'status' => 1])->get()->getResultArray();
                $checkin = array_combine(array_column($checkin, 'guest_id'), $checkin);
            } else {
                
                $guests_unassigned = $this->guestmodel->findAll();
                $guests_unassigned = array_combine(array_column($guests_unassigned, 'id'), $guests_unassigned);
            }

            
            if(count($group_ids) > 0) {
                $groups = $this->groupmodel->whereIn('id', $group_ids)->findAll();
                $groups = array_combine(array_column($groups, 'id'), $groups);    
            }
            
            $this->data['guests'] = $guests;
            $this->data['guests_unassigned'] = $guests_unassigned;
            $this->data['groups'] = $groups;
            $this->data['checkin'] = $checkin;
        
        $this->data['list'] = $list; 

        echo view('layout', $this->data);
    }

    /* Stage related functions*/

    public function stageMapping($session_id) {
        $session = $this->sessionmodel->find($session_id);
        $session['stage'] = json_decode($session['stage']);
        $nSeats = $session['stage'][2];
        $seatings = $this->stagemodel->where('session_id', $session_id)->findAll();
        $booked_seats = array_flip(array_column($seatings, 'stage', 'id'));

        $pattern_concrete = array();
        $rCount = 0;
        foreach($session['stage'] as $row_key => $row):
            $rCount++;
            $tab = array();
            for($i = 1; $i<= $row; $i++):
                if(isset($booked_seats['R' . $rCount . 'S' . $i]))
                    $tab[$i] = $booked_seats['R' . $rCount . 'S' . $i];
                else
                    $tab[$i] = null;
            endfor;
            $pattern_concrete[$row_key+1] = $tab;
        endforeach;
        return $pattern_concrete;
    }

    public function groupStage($first_seat, $session_id, $group_id) {
        $seat_split = splitStage($first_seat);
        $group = $this->groupmodel->find($group_id);
        $pattern_concrete = $this->stageMapping($session_id);
        $keys = array_keys($pattern_concrete);
        $key = array_search($seat_split['R'], $keys);
        $seat = (int)$seat_split['S'];
        $avail_seats = array();
        $counter = 0;

        // var_dump($seat_split['S'], $pattern_concrete, $keys); exit;
        do{
            foreach($pattern_concrete[$keys[$key]] as $index => $tab):
                if($index < $seat) continue;
                if($tab == null) {
                    $avail_seats[] = "R" . $keys[$key] . "S" . $index;
                    $counter++;
                    if($counter == $group['nGuests']) break;
                }
            endforeach;
            $index = 1;
            $key++;
        } while(isset($keys[$key]) && $counter < $group['nGuests']);
        return $avail_seats;
    }

    public function stage($session_id) {
        $sess = $this->sessionmodel->find($session_id);
        if($sess == null)
            return redirect()->to('/session/list');

        if($sess['stage'] == null)
            return redirect()->to('set-stage/' . $session_id);

        $data = $this->generate_arrays('stage', $session_id);
        $this->data = array_merge($this->data, $data);
        $this->data['each_row'] = json_decode($sess['stage']);
        $this->data['id'] = $session_id;
        $this->data['room_type'] = 'stage';

        echo view('plans/stage', $this->data);   
    }
    public function set_stage($session_id) {
        $this->data['id'] = $session_id;
        echo view('plans/set_stage', $this->data);   
    }

    public function save_stage_setup() {

        $data = [
            'stage'     => json_encode($this->request->getVar('people'))
        ];

        $session_id = $this->request->getVar('id');
        $this->sessionmodel->update($session_id, $data);
        $this->stagemodel->where('session_id', $session_id)->delete();

        $this->session->setFlashdata('msg', 'Stage setup updated!');
        return redirect()->to('stage/' . $session_id);
    }

    public function assign_stage($session_id) {

        $guest_id = $this->request->getVar('id');
        $seating_no = $this->request->getVar('seat_no');

        if(str_starts_with($guest_id, "G")) {
            $group_id = substr($guest_id, 1);
            $group = $this->groupmodel->find($group_id);
            $this->stagemodel->where('group_id', $group_id)->delete();
            $group_seatings = $this->groupStage($seating_no, $session_id, $group_id);
            $data = [];
            foreach($group_seatings as $seat):
                $data[] = ['session_id' => $session_id, 'group_id' => $group_id, 'stage' => $seat];                
            endforeach;
            $this->stagemodel->insertBatch($data);
            $this->session->setFlashdata('msg', count($group_seatings) . ' seats assigned to this group of ' . $group['nGuests']);
            
        } else {
            $data = ['session_id' => $session_id, 'guest_id' => $guest_id, 'stage' => $seating_no];    
            $this->stagemodel->where('guest_id', $guest_id)->delete();
            $this->stagemodel->save($data);
            $this->session->setFlashdata('msg', 'The Seat Assigned!');
        }
        return redirect()->to('stage/' . $session_id);
    }
    public function remove_stage($type, $id, $session_id) {

        if($type == 'guest')
            $this->stagemodel->where(['guest_id' => $id, 'session_id' => $session_id])->delete();
        else
            $this->stagemodel->where(['group_id' => $id, 'session_id' => $session_id])->delete();


        $this->session->setFlashdata('msg', 'Stage Freed!');
        return redirect()->to('stage/' . $session_id);
    }

    /* Seating related functions*/

    public function seating_plan($id) {
        $sess = $this->sessionmodel->find($id);
        if($sess == null)
            return redirect()->to('/session/list');

        if($sess['seating'] == null)
            return redirect()->to('set-seating-plan/' . $id);
        $data = $this->generate_arrays('seating', $id);
        $this->data = array_merge($this->data, $data);
        $this->data['plan'] = json_decode($sess['seating']);
        $this->data['plan'][1] = (int)$this->data['plan'][1];
        $this->data['plan'][2] = (int)$this->data['plan'][2];

        $this->data['rowsSeries'] = rowsSeries($id);
        $this->data['id'] = $id;
        $this->data['room_type'] = 'seating';
        $this->data['booked_ids'] = array_column($this->data['booked'], 'id');
        // echo "<pre>"; print_r($this->data); echo "</pre>"; exit;
        echo view('plans/seating-plan', $this->data);
    }

    public function set_seating_plan($session_id) {
        $data = $this->sessionmodel->find($session_id);
        array_push($this->data, $data);
        $this->data['session_id'] = $session_id;
        echo view('plans/set-seating-plan', $this->data);      
    }
    
    public function seatsMapping($session_id) {
        $session = $this->sessionmodel->find($session_id);
        $session['seating'] = json_decode($session['seating']);
        $nSeats = $session['seating'][2];
        $seatings = $this->seatingmodel->where('session_id', $session_id)->findAll();
        $booked_seats = array_flip(array_column($seatings, 'seating', 'id'));
        
        if($session['seating'][0] == 's')
            $pattern = rowsSeries($session_id);
        else {
            // $pattern = [range(1, $session['seating'][1])];
            $pattern = rowsSeries($session_id);
        }
        $pattern_concrete = array();
        foreach($pattern as $row_key => $row):
            foreach($row as $table_key => $table):
                if($table[0] == null || $table[0] == "") continue;
                $tab = array();
                for($i = 1; $i<= $table[1]; $i++):
                    if(isset($booked_seats['T' . $table[1] . 'S' . $i]))
                        $tab[$i] = $booked_seats['T' . $table[1] . 'S' . $i];
                    else
                        $tab[$i] = null;
                endfor;
                $pattern_concrete[$table[0]] = $tab;
            endforeach;
        endforeach;

        return $pattern_concrete;
    }
    
    
    public function groupSeatings($first_seat, $session_id, $group_id) {    
        $seat_split = splitSeating($first_seat);
        $group = $this->groupmodel->find($group_id);
        $pattern_concrete = $this->seatsMapping($session_id);
        $keys = array_keys($pattern_concrete);
        $key = array_search($seat_split['T'], $keys);
        $avail_seats = array();
        $counter = 0;
        $key = $keys[$key];
        do{
            foreach($pattern_concrete[$key] as $index => $tab):
                $table = $key;
                if($table >= 1 && $table <= 9) $table = "0" . $table;
                
                $seat = $index;
                if($seat >= 1 && $seat <= 9) $seat = "0" . $seat;
                
                $avail_seats[] = "T" . $table . "S" . $seat;
                $counter++;
                if($counter == $group['nGuests']) break;
            endforeach;
            $key++;
        } while(isset($pattern_concrete[$key]) && $counter < $group['nGuests']); 
        return $avail_seats;
    }
    
    // public function groupSeatings($first_seat, $session_id, $group_id) {    
    //     $seat_split = splitSeating($first_seat);
    //     $group = $this->groupmodel->find($group_id);
    //     $pattern_concrete = $this->seatsMapping($session_id);
    //     $keys = array_keys($pattern_concrete);
    //     $key = array_search($seat_split['T'], $keys);
    //     // echo "<pre>"; print_r($pattern_concrete); echo "</pre>";
    //     $avail_seats = array();
    //     $counter = 0;
    //     do{
    //         foreach($pattern_concrete[$keys[$key]] as $index => $tab):
    //             if($tab == null) {
    //                 $avail_seats[] = "T" . $keys[$key] . "S" . $index;
    //                 $counter++;
    //                 if($counter == $group['nGuests']) break;
    //             }
    //         endforeach;
    //         $key++;
    //     } while(isset($keys[$key]) && $counter < $group['nGuests']); 
    //     echo "<pre>"; print_r($avail_seats); echo "</pre>";
    //     exit;
    //     return $avail_seats;
    // }

    public function assign_seating($session_id) {
        $guest_id = $this->request->getVar('id');
        $seating_no = $this->request->getVar('seat_no');

        if(str_starts_with($guest_id, "G")) {
            $group_id = substr($guest_id, 1);
            $group = $this->groupmodel->find($group_id);
            $this->seatingmodel->where('group_id', $group_id)->delete();
            $group_seatings = $this->groupSeatings($seating_no, $session_id, $group_id);
            $data = [];
            foreach($group_seatings as $seat):
                $this->seatingmodel->where(['session_id' => $session_id, 'seating' => $seat])->delete();
                $data[] = ['session_id' => $session_id, 'group_id' => $group_id, 'seating' => $seat];                
            endforeach;
            $this->seatingmodel->insertBatch($data);
            $this->session->setFlashdata('msg', count($group_seatings) . ' seats assigned to this group of ' . $group['nGuests']);
            
        } else {
            $data = ['session_id' => $session_id, 'guest_id' => $guest_id, 'seating' => $seating_no];    
            $this->seatingmodel->where('guest_id', $guest_id)->delete();
            $this->seatingmodel->save($data);
            $this->session->setFlashdata('msg', 'The Seat Assigned!');
        }

        
        
        return redirect()->to('seating-plan/' . $session_id);
    }

    public function save_seating_plan() {

        $data = [
            'seating'     => json_encode(array($this->request->getVar('table_type'), $this->request->getVar('tables'), $this->request->getVar('seats')))
        ];
        $session_id = $this->request->getVar('session_id');
        

        $this->sessionmodel->update($session_id, $data);
        $this->seatingmodel->where('session_id', $session_id)->delete();

        $this->session->setFlashdata('msg', 'Seating plan updated!');
        return redirect()->to('seating-plan/' . $session_id);
    }


    public function download_plan($type) {
        $session_id = $this->request->getVar('session_id'); 
        $result = $this->generate_arrays($type, $session_id);
        $fields = $this->request->getVar('fields');
        if($fields)
            $fields = array_flip($fields);
        $file_type = $this->request->getVar('type');
        if($file_type == "PDF"){
            $dompdf = new Dompdf();
            $result['fields'] = $fields;
            $html = view('plans/seating-plan-download', $result);
            $dompdf->loadHtml($html);
            $dompdf->render();
            $dompdf->stream($type . '_plan.pdf', [ 'Attachment' => true ]);
        } else {

            $row = 1;
            $spreadsheet = new Spreadsheet();
            $activeWorksheet = $spreadsheet->getActiveSheet(); 
            $alphabets = array('A', 'B', 'C', 'D', 'E', 'F');
            foreach($fields as $key => $val):
                $activeWorksheet->setCellValue($alphabets[$val] . $row, $key);    
            endforeach;

            foreach($result['booked'] as $booking) {
                $row++;
                foreach($fields as $key => $val):
                    if($key == "profile_image") {
                        $activeWorksheet->setCellValue($alphabets[$val] . $row, base_url('assets/images/profiles/' . $booking[$key]));
                    }
                    else
                        $activeWorksheet->setCellValue($alphabets[$val] . $row, $booking[$key]);    
                endforeach;
            }   

        $writer = new Xlsx($spreadsheet);
        $fileName = $type . "_plan.xlsx";
                header('Content-Encoding: UTF-8');
                header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=UTF-8');
                header('Content-Disposition: attachment; filename="'. urlencode($fileName).'"');
                $writer->save('php://output');
        $writer->save('hello world.xlsx');

        }
        exit;
        
    }

    public function remove_seating($type, $id, $session_id) {
        if($type == 'guest'):
            $this->seatingmodel->where(['guest_id' => $id, 'session_id' => $session_id])->delete();
            $this->checkinmodel->where(['guest_id' => $id, 'session_id' => $session_id])->set('checked_in', 0)->update();
        elseif($type == 'group'):
            $this->seatingmodel->where(['group_id' => $id, 'session_id' => $session_id])->delete();
        endif;
        $this->session->setFlashdata('msg', 'Seat(s) reset!');
        return redirect()->to('seating-plan/' . $session_id);
    }
    
}
