<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use MongoDB\Client as MongoDBClient;

use Illuminate\Support\Carbon;
use MongoDB\BSON\ObjectID;
use MongoDB\BSON\UTCDateTime;
use \DateInterval;
use \DateTime;


class AttendanceController extends Controller
{
    protected $mongoDB;

    public function __construct(MongoDBClient $mongoDB)
    {
        $this->middleware('auth');
        $this->mongoDB = $mongoDB;
    }

    public function index($camera_id)
    {

        $collections = $this->mongoDB->dataprocess->match_faces;
        $result = $collections->find(['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)])->toArray();

        return view("attendance.att_list", compact('result'));
    }

    public function setup_attendance($camera_id)
    {
        $collections = $this->mongoDB->dataprocess->cameras;
        $result = $collections->findOne(['_id' => new \MongoDB\BSON\ObjectID($camera_id)]);

        $collectionsdraw = $this->mongoDB->dataprocess->attendance_draw_lines;
        $draw = $collectionsdraw->findOne(['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]);

        $collectionsStreamingInfo = $this->mongoDB->dataprocess->steaming_info;
        $getStreamInfo = $collectionsStreamingInfo->findOne(['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]);
        $streamInfo = $getStreamInfo->info->streams;


        if (!$result) {
            session()->flash('error', "Sorry, Invalid data");
            return back();
        }
        session()->put('camera_id', $camera_id);
        return view("attendance.new_setup", compact('result', 'camera_id', 'draw', 'streamInfo'));
    }

    public function store_lines(Request $request)
    {

        if (
            $request->start_x == null || $request->start_y == null || $request->end_x == null || $request->end_y == null
            || $request->color == null || $request->width == null
        ) {

            $data = [
                'status' => 204,
                'message' => 'Invalid line paramters',
            ];
            return json_encode($data);
        }


        if (!session('camera_id')) {
            $data = [
                'status' => 204,
                'message' => 'Invalid camera stream',
            ];
            return json_encode($data);
        }

        $data = [];
        $data = $request->all();
        $data['camera_id'] = new \MongoDB\BSON\ObjectID(session()->get('camera_id'));
        $data['user_id'] = auth()->user()->uuid;

        $collections = $this->mongoDB->dataprocess->attendance_draw_lines;

        $filter = ['camera_id' => new \MongoDB\BSON\ObjectID($data['camera_id'])];

        // Define the update operation
        $update = [
            '$set' => $data
        ];

        $result = $collections->updateOne($filter, $update, ['upsert' => true]);

        if ($result->getMatchedCount() > 0) {

            $data = [
                'status' => 200,
                'message' => 'Stream successfully saved',
            ];
        } else {

            $data = [
                'status' => 204,
                'message' => 'Sorry try again.',
            ];
        }
        return json_encode($data);
    }

    public function access_control_attendance_sys()
    {
        try {
            $collection = $this->mongoDB->dataprocess->cameras;

            $pipeline = [
                [
                    '$match' => [
                        'user_id' => auth()->user()->uuid,
                        'region_id' => ['$exists' => true, '$ne' => null],
                        'is_allow_attendance' => 1,
                    ]
                ],
                [
                    '$lookup' => [
                        'from' => 'regions',
                        'let' => ['region_id' => ['$toObjectId' => '$region_id']],
                        'pipeline' => [
                            ['$match' => ['$expr' => ['$eq' => ['$_id', '$$region_id']]]]
                        ],
                        'as' => 'region'
                    ]
                ],
                ['$unwind' => '$region'],
                [
                    '$addFields' => [
                        'region_name' => '$region.name',
                        'region_description' => '$region.description'
                    ]
                ],
                ['$sort' => ['_id' => -1]]
            ];

            $cameras = $collection->aggregate($pipeline)->toArray();
            // dd($cameras);

        } catch (Exception $e) {
            dd("An error occurred: " . $e->getMessage());
        }

        // dd($cameras);
        return view("attendance.access_control", compact('cameras'));
    }


    public function object_counter()
    {

        $collection = $this->mongoDB->dataprocess->attendee_counts;
        $collection_cameras = $this->mongoDB->dataprocess->cameras;
        $collection_region = $this->mongoDB->dataprocess->regions;
        $collection_photo_frame_detect = $this->mongoDB->dataprocess->photo_frame_detect;


        $uuid = auth()->user()->uuid;

        $options = [
            'sort' => ['created_at' => -1] // Sort by created_at in descending order
        ];

        $getCameras = $collection_cameras->find(
            [
                'user_id' => $uuid,
                'is_allow_count_attendees' => 1
            ]
            ,
            $options
        )->toArray();

        // dd($getCameras);

        foreach ($getCameras as $a) { // Use reference to modify $a directly
            // Attempt to find the camera record by camera_id
            $getAttendee = $collection->findOne(
                ['camera_id' => new \MongoDB\BSON\ObjectID($a['_id'])]
            );

            $getRegion = $collection_region->findOne(
                ['_id' => new \MongoDB\BSON\ObjectID($a['region_id'])]
            );


            $a['camera_id'] = $a['_id'];


            // ~~~ ADDING REGION DETAIL ~~~


            $a['regionInfo'] = $getRegion ?? null;



            // ~~~ ADDING OBJECT INFO ~~~

            $photo_frame_detect = $collection_photo_frame_detect->findOne(
                ['camera_id' => new \MongoDB\BSON\ObjectID($a['_id'])],
            );

            $a['objectInfo'] = null;

            $a['attendeeInfo'] = $photo_frame_detect['people_count'] ?? 0;


            if ($photo_frame_detect) {
                $a['objectInfo'] = $photo_frame_detect['info'];
            }
        }

        $records = $getCameras;

        // dd($records);

        return view("attendance.object_counter", compact('records'));
    }


    public function monitor_attendance($camera_id)
    {
        return view('attendance.monitor_attendee', compact('camera_id'));
    }


    public function attendance_report($camera_id, $page = 1)
    {

        $collection = $this->mongoDB->dataprocess->face_for_search;
        $collection_match_faces = $this->mongoDB->dataprocess->match_faces;
        $collection_cameras = $this->mongoDB->dataprocess->cameras;
        $collection_regions = $this->mongoDB->dataprocess->regions;

        $limit = 10; // Number of items per page

        // Fetch records with pagination
        $getRecord = $collection->find(
            ['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)],
            [
                'limit' => $limit,
                'skip' => ($page - 1) * $limit // Calculate the number of documents to skip for pagination
            ]
        );

        $records = iterator_to_array($getRecord);

        foreach ($records as &$rec) { // Use reference (&) to modify the original array
            // Count face matches for the current record
            $faceMatchCount = $collection_match_faces->count(
                ['match_face_id' => new \MongoDB\BSON\ObjectID($rec['_id'])]
            );

            // Fetch camera information based on camera ID from the record
            $cameraInfo = $collection_cameras->findOne(
                ['_id' => new \MongoDB\BSON\ObjectID($rec['camera_id'])]
            );

            // Fetch region information based on region ID from the record
            $regionInfo = $collection_regions->findOne(
                ['_id' => new \MongoDB\BSON\ObjectID($rec['region_id'])]
            );

            // Add camera and region info to the record
            $rec['camera_name'] = $cameraInfo['cameraname'];
            $rec['region_name'] = $regionInfo['region'];

            // Determine presence based on face match count
            $rec['is_present'] = ($faceMatchCount > 0) ? 1 : 0;
        }

        // Count total items for pagination
        $totalItems = $collection->count(['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]);
        $totalPages = ceil($totalItems / $limit);

        // Return view with data
        return view("attendance.report", compact('records', 'page', 'totalPages'));
    }

    public function match_faces($face_id)
    {
        $collection_face_for_search = $this->mongoDB->dataprocess->face_for_search;
        $collection_camera = $this->mongoDB->dataprocess->cameras;
        $collection_match_faces = $this->mongoDB->dataprocess->match_faces;
        $collection_match_faces = $this->mongoDB->dataprocess->match_faces;



        $faceMatch = $collection_match_faces->find(
            ['match_face_id' => new \MongoDB\BSON\ObjectID($face_id)],
            // [
            //     'projection' => ['face_photo' => 1, '_id' => 0] // Specify the fields to include
            // ]
        );

        $faceSearch = $collection_face_for_search->findOne(
            ['_id' => new \MongoDB\BSON\ObjectID($face_id)],
            // [
            //     'projection' => ['face_photo' => 1, '_id' => 0] // Specify the fields to include
            // ]
        );


        $record = iterator_to_array($faceMatch);

        foreach ($record as $r) {
            $camera = $collection_camera->findOne(
                ['_id' => new \MongoDB\BSON\ObjectID($r['camera_id'])],
            );

            $r['camera_name'] = $camera['cameraname'];

            $r['faceInfo'] = $faceSearch;
        }


        return $record;
    }



    public function view_attendee($frame_id)
    {
        // Get the photo face detect collection
        $collection_photo_face_detect = $this->mongoDB->dataprocess->photo_face_detect;


        $page = 1;
        $limit = 10;

        // Find the corresponding photo face detect record
        $photo_face_record_cursor = $collection_photo_face_detect->find(
            ['main_frame_id' => new \MongoDB\BSON\ObjectID($frame_id)],
            ['projection' => ['detected_face_frame' => 1, '_id' => 0]], // Only fetch the detected_face_frame field
            // [
            //     'limit' => $limit,
            //     'skip' => ($page - 1) * $limit // Calculate the number of documents to skip for pagination
            // ]
        );

        $photo_face_record = iterator_to_array($photo_face_record_cursor);

        return $photo_face_record;
    }

    public function object_counter_detail_view($camera_id)
    {

        // ~~~ get camera information ~~~ //

        $collection_cameras = $this->mongoDB->dataprocess->cameras;

        $camera = $collection_cameras->findOne(
            ['_id' => new \MongoDB\BSON\ObjectID($camera_id)],
        );

        // ~~~ get region information ~~~ //

        $collection_regions = $this->mongoDB->dataprocess->regions;

        $region = $collection_regions->findOne(
            ['_id' => new \MongoDB\BSON\ObjectID($camera['region_id'])],
        );


        return view('attendance.object_counter_detail', compact('camera', 'region'));
    }

    // public function object_counter_detail($camera_id, $page = 1)
    // {

    //     $limit = 10;

    //     // ~~~ get camera information ~~~ //

    //     $collection_cameras = $this->mongoDB->dataprocess->cameras;

    //     $camera = $collection_cameras->findOne(
    //         ['_id' => new \MongoDB\BSON\ObjectID($camera_id)],
    //     );

    //     // ~~~ get region information ~~~ //

    //     $collection_regions = $this->mongoDB->dataprocess->regions;

    //     $region = $collection_regions->findOne(
    //         ['_id' => new \MongoDB\BSON\ObjectID($camera['region_id'])],
    //     );


    //     // ~~~ get attendee_list_cross_line records based on camera_id ~~~ //

    //     $collection_attendee_list_cross_line = $this->mongoDB->dataprocess->attendee_list_cross_line;


    //     // Fetch the first record for the specified camera_id
    //     $firstRecord = $collection_attendee_list_cross_line->findOne(
    //         ['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]
    //     );

    //     // Set the desired number of minutes to add
    //     $minutesToAdd = 5; // Change this to the number of minutes you want to add


    //     $startTime = $firstRecord['created_at']->toDateTime();


    //     if ($page > 1) {
    //         $startTime = clone $startTime;
    //         $startTime->add(new DateInterval('PT' . ($minutesToAdd * $page) . 'M'));
    //     }

    //     $endTime = clone $startTime;
    //     $endTime->add(new DateInterval('PT' . $minutesToAdd . 'M'));

    //     // Fetch records within the specified time range
    //     $attendee_list_cross_line_cursor = $collection_attendee_list_cross_line->find(
    //         [
    //             'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
    //             'created_at' => [
    //                 '$gte' => new UTCDateTime($startTime),
    //                 '$lte' => new UTCDateTime($endTime)
    //             ]
    //         ]
    //     );





    //     // $attendee_list_cross_line_cursor = $collection_attendee_list_cross_line->find(
    //     //     ['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)],
    //     //     [
    //     //         'limit' => $limit,
    //     //         'skip' => ($page - 1) * $limit
    //     //     ]

    //     // );





    //     $collection_photo_face_detect = $this->mongoDB->dataprocess->photo_face_detect;
    //     $collection_photo_frame_detect = $this->mongoDB->dataprocess->photo_frame_detect;



    //     $cross_line_list = [];

    //     foreach ($attendee_list_cross_line_cursor as $cross_line) {



    //         $photo_frame_detect = $collection_photo_frame_detect->findOne(
    //             ['_id' => new \MongoDB\BSON\ObjectID($cross_line['frame_id'])],
    //         );

    //         $detectedCount = $collection_attendee_list_cross_line->count(['frame_id' => new \MongoDB\BSON\ObjectID($cross_line['frame_id'])]);


    //         // ~~~ add new key in $attendee_list_cross_line_cursor ~~~ //

    //         $cross_line['frame_img_base64'] = isset($photo_frame_detect['people_count_image']) ? $photo_frame_detect['people_count_image'] : $photo_frame_detect['photo_frame'] ;
    //         $cross_line['frame_time'] = $photo_frame_detect['created_at'];
    //         $cross_line['detected_people_count'] = $photo_frame_detect['people_count'] ?? 0;
    //         // $cross_line['detected_people_count'] = $detectedCount;
    //         $cross_line['objectInfo'] = $photo_frame_detect['info'];



    //         $cross_line_list[] = json_decode(json_encode($cross_line), true);

    //     }

    //     $totalItems = $collection_attendee_list_cross_line->count(['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]);
    //     $totalPages = ceil($totalItems / $limit);

    //     $records = $cross_line_list;


    //     return [
    //         "records" => $records,
    //         "totalItems" => $totalItems,
    //         "totalPages" => $totalPages,
    //     ];
    // }

    public function object_counter_detail($camera_id, $page = 1)
    {

        $limit = 10;

        // ~~~ get camera information ~~~ //

        $collection_cameras = $this->mongoDB->dataprocess->cameras;

        $camera = $collection_cameras->findOne(
            ['_id' => new \MongoDB\BSON\ObjectID($camera_id)],
        );

        // ~~~ get region information ~~~ //

        $collection_regions = $this->mongoDB->dataprocess->regions;

        $region = $collection_regions->findOne(
            ['_id' => new \MongoDB\BSON\ObjectID($camera['region_id'])],
        );


        // ~~~ get collection_photo_frame_detect records based on camera_id ~~~ //

        $collection_photo_frame_detect = $this->mongoDB->dataprocess->photo_frame_detect;

        $collection_photo_face_detect = $this->mongoDB->dataprocess->photo_face_detect;



        // Fetch the first record for the specified camera_id


        // $firstRecord = $collection_photo_frame_detect->findOne(
        //     ['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]
        // );

        // // Set the desired number of minutes to add
        // $minutesToAdd = 5; // Change this to the number of minutes you want to add


        // $startTime = $firstRecord['created_at']->toDateTime();


        // if ($page > 1) {
        //     $startTime = clone $startTime;
        //     $startTime->add(new DateInterval('PT' . ($minutesToAdd * $page) . 'M'));
        // }

        // $endTime = clone $startTime;
        // $endTime->add(new DateInterval('PT' . $minutesToAdd . 'M'));

        // // Fetch records within the specified time range
        // $photo_frame_records = $collection_photo_frame_detect->find(
        //     [
        //         'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
        //         'created_at' => [
        //             '$gte' => new UTCDateTime($startTime),
        //             '$lte' => new UTCDateTime($endTime)
        //         ]
        //     ]
        // );


        $recordsPerPage = 5; // Number of records to fetch per page
        $skipRecords = ($page - 1) * $recordsPerPage; // Calculate how many records to skip

        // Fetch records with pagination
        $photo_frame_records = $collection_photo_frame_detect->find(
            [
                'camera_id' => new \MongoDB\BSON\ObjectID($camera_id)
            ],
            [
                'limit' => $recordsPerPage,
                'skip' => $skipRecords
            ]
        );

        $photo_frmae_list = [];

        foreach ($photo_frame_records as $photo_frmae) {


            $photo_frame_detect = $photo_frmae;



            $photo_frmae['frame_img_base64'] = $photo_frame_detect['photo_frame'];
            $photo_frmae['frame_img_count_base64'] = isset($photo_frame_detect['people_count_image']) ? $photo_frame_detect['people_count_image'] : $photo_frame_detect['photo_frame'];
            $photo_frmae['frame_time'] = $photo_frame_detect['created_at'];
            $photo_frmae['detected_people_count'] = $photo_frame_detect['people_count'] ?? 0;
            // $photo_frmae['detected_people_count'] = $detectedCount;
            $photo_frmae['objectInfo'] = $photo_frame_detect['info'];



            $photo_frmae_list[] = json_decode(json_encode($photo_frmae), true);

        }


        $photo_face_record = iterator_to_array($photo_frmae_list);


        $totalItems = $collection_photo_frame_detect->count(['camera_id' => new \MongoDB\BSON\ObjectID($camera_id)]);
        $totalPages = ceil($totalItems / $limit);

        $records = $photo_frmae_list;


        return [
            "records" => $records,
            "totalItems" => $totalItems,
            "totalPages" => $totalPages,
        ];
    }
}
