<?php

namespace App\Http\Controllers;

use App\Helper\ApiHelper;
use App\Helper\Encryption;
use App\Helper\HelperData;
use App\Helper\MongoHelper;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use MongoDB\Client as MongoDBClient;
use MongoDB\BSON\UTCDateTime;


class AddDataController extends Controller
{

    protected $mongoDB;
    protected $mongoHelper;

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


    public function edit_origin($id)
    {


        $data = null;
        $collections = $this->mongoDB->dataprocess->regions;
        $result = $collections->find(['_id' => new \MongoDB\BSON\ObjectID($id)]);
        foreach ($result as $list) {
            $data = $list;
        }
        return view("add.edit_region", compact('data'));
    }


    /** Get All Regions */

    public function all_regions_views()
    {

        $collections = $this->mongoDB->dataprocess->regions;
        $result = $collections->find([
            'uuid'=>Auth::user()->uuid
        ], [
            'sort' => ['_id' => -1]
        ]);

        return view("add.regions_all_list", compact('result'));
    }

    public function add_region_view()
    {
        return view("add.add_region");
    }


    public function update_region(Request $request)
    {
        if (!$request->region || !$request->id) {
            session()->flash("error", "Missing data");
            return back();
        }


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

        // Convert the formatted date to MongoDB BSON DateTime

        // Get the collection instance

        $updateData = [
            '$set' => [
                'region' => $request->region,
                'status' => ($request->status) ? 1 : 0,
            ]
            // Add other fields and their values
        ];

        // Insert the new document into the collection
        $updateResult = $collection->updateOne(
            ['_id' => new \MongoDB\BSON\ObjectID($request->id)],
            $updateData
        );

        // Check if the insertion was successful
        if ($updateResult->getModifiedCount() > 0) {
            // Get the ID of the inserted document
            if ($updateResult->getModifiedCount() > 0) {
                session()->flash("success", "Region updated successfully");
            } else {
                session()->flash("error", "No modifications made");
            }
        }

        return redirect(route('all.rigions.lists'));
    }

    public function add_new_region(Request $request)
    {
        if (!$request->region) {
            session()->flash("error", "Missing data");
            return back();
        }

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

        $currentDateTime = date('Y-m-d H:i:s');

        // Convert the formatted date to MongoDB BSON DateTime
        $dateTime = new UTCDateTime(strtotime($currentDateTime) * 1000);

        // Get the collection instance

        $dataToInsert = [
            'region' => $request->region,
            'status' => ($request->status) ? 1 : 0,
            'created_at' => $dateTime,
            'uuid' => Auth::user()->uuid
        ];

        // Insert the new document into the collection
        $insertResult = $collection->insertOne($dataToInsert);

        // Check if the insertion was successful
        if ($insertResult->getInsertedCount() > 0) {
            // Get the ID of the inserted document
            $insertedId = $insertResult->getInsertedId();
            session()->flash("success", "Region added successfully");
        } else {
            session()->flash("error", "Sorry try again");
        }

        return redirect(route('all.rigions.lists'));
    }

    /**================= Cameras Functions  ============= */

    public function view_all_cameras($region)
    {

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

        $pipeline = [
            [
                '$match' => [
                    'user_id' => auth()->user()->uuid,
                    'region_id' => new \MongoDB\BSON\ObjectID($region)
                ]
            ],
            [
                '$lookup' => [
                    'from' => 'regions',
                    'localField' => 'region_id',
                    'foreignField' => '_id',
                    'as' => 'region'
                ]
            ],
            ['$unwind' => '$region'],
            [
                '$addFields' => [
                    'region_name' => '$region.name',
                    'region_description' => '$region.description'
                ]
            ],
            ['$sort' => ['_id' => -1]]
        ];

        $cameras = $collection->aggregate($pipeline)->toArray();
        return view("add.cameras_list", compact('cameras', 'region'));
    }

    public function view_only_cameras()
    {

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

        // $cameras = $collection->find(
        //     [
        //         'user_id' => auth()->user()->uuid,
        //     ],
        //     [
        //         'sort' => ['_id' => -1],
        //         //'skip' => $skip, // Skip the specified number of documents
        //         //'limit' => $perPage, // Limit the number of documents per page
        //     ]
        // );
        //return  $cameras->toArray();



        try {
            $collection = $this->mongoDB->dataprocess->cameras;

            $pipeline = [
                [
                    '$match' => [
                        'user_id' => auth()->user()->uuid,
                        'region_id' => ['$exists' => true, '$ne' => null]
                    ]
                ],
                [
                    '$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());
        }


        return view("add.cameras_list", compact('cameras'));
    }


    public function add_camera_view($id)
    {
        $regions = $this->mongoDB->dataprocess->regions;
        $regions = $regions->find(['_id' => new \MongoDB\BSON\ObjectID($id)]);
        $regions = $regions->toArray();

        if (count($regions) > 0) {
            return view("add.add_camera", compact('id', 'regions'));
        } else {
            session()->flash('error', "Invalid region data");
            return back();
        }
    }


    public function add_streamWithCamera(){
        $regions = $this->mongoDB->dataprocess->regions;
    $allRegions = $regions->find()->toArray();

    return view("add.add_camera_and_region", compact('allRegions'));
    }


    public function save_streamWithCamera(request $request){
        // dd($request);


        $request->validate([
            // 'region' => 'required|string',
            'camera' => 'required|string',
            'url' => 'required|url',
        ]);

        //  ~~~~~ add region ~~~~~

        if($request->has('region')  && $request->region != ""){

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

        $currentDateTime = date('Y-m-d H:i:s');

        // Convert the formatted date to MongoDB BSON DateTime
        $dateTime = new UTCDateTime(strtotime($currentDateTime) * 1000);

        // Get the collection instance

        $dataToInsert = [
            'region' => $request->region,
            'status' => ($request->status) ? 1 : 0,
            'created_at' => $dateTime,
            'uuid' => Auth::user()->uuid
        ];

        // Insert the new document into the collection
        $insertResult = $collection->insertOne($dataToInsert);
    }

        // ~~~~~ add camera ~~~~~~
        $region_id  = $request->region_id;

        if (isset($insertResult) && $insertResult->getInsertedCount() > 0) {
            $region_id  = $insertResult->getInsertedId();
        }

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

        $currentDateTime = date('Y-m-d H:i:s');

        // Convert the formatted date to MongoDB BSON DateTime
        $dateTime = new UTCDateTime(strtotime($currentDateTime) * 1000);

        // Get the collection instance

        $dataToInsert = [
            'cameraname' => $request->camera,
            'stream_url' => $request->url,
            'status' => ($request->status) ? 1 : 0,
            'region_id' => new \MongoDB\BSON\ObjectID($region_id),
            'created_at' => $dateTime,
            'user_id' => auth()->user()->uuid,
            'is_virtial_wall' => 1,
            // Add other fields and their values
        ];

        // Insert the new document into the collection
        $insertResult = $collection->insertOne($dataToInsert);

        // Check if the insertion was successful
        if ($insertResult->getInsertedCount() > 0) {
            // Get the ID of the inserted document
            $insertedId = $insertResult->getInsertedId();
            $lastid =  json_encode($insertedId, false);
            $data = json_decode($lastid, true); // Decode the JSON string
            // Access the value associated with the key '$oid'
            $oidValue = $data['$oid'];
            // Now $oidValue contains the ObjectId value
            $stream_name = preg_replace("/[^a-zA-Z0-9]/", "", $request->camera);

            $params = [
                'stream_name' => $stream_name,
                'stream_url' => $request->url,
                'request_id' => "11111",
                'camera_id' => $oidValue,
                'region_id' => $region_id,
                'access_token' => '123456',
            ];



            // Encrypt user  information
            $enc = Encryption::encrypt(Auth()->user()->uuid);

            $encryptedData = $enc['encryptedData'];
            $iv =  $enc['iv'];

            $params['encrypt'] = $enc['encryptedData'];
            $params['iv'] = $enc['iv'];
            // echo json_encode($params); die();
            // Create VM API
            $response = ApiHelper::create_stream_vm($params, $encryptedData, $iv);

            $statusCode = $response->getStatusCode();

            if ($statusCode == 200) {
                $body  = $response->getBody()->getContents();
                $data = json_decode($body, true);

                if (isset($data['error'])) {
                    if ($data['error'] == true) {
                        session()->flash('error', $data['message']);
                    } else {


                        //==========================
                        // Insert stream settings
                        //==========================

                        $collection_camera_stream = $this->mongoDB->dataprocess->camera_stream_settings;
                        $data = [
                            'user_id' => auth()->user()->uuid,
                            'camera_id' => new \MongoDB\BSON\ObjectID($oidValue),
                            'extract_frame_time' => 10
                        ];
                        $result =  $this->mongoHelper->insertDataToCollection($data, $collection_camera_stream);

                        session()->flash("success", "Stream created successfully");
                        //  session()->flash('success',$data['message']);
                    }
                } else {
                    session()->flash('error', 'Invalid data set to create virtial machine');
                }
            } else {
                session()->flash('error', 'Invalid data set to create virtial machine');
            }
        } else {
            session()->flash("error", "Sorry try again");
        }

        return redirect(route('all.cameras.lists', $request->region));

    }

    public function add_camera2_view()
    {
        $regions = $this->mongoDB->dataprocess->regions;
        $regions = $regions->find([]);
        return view("add.add_camera_with_rigion", compact('regions'));
    }

    /**
     * Add new camera
     */

    public function add_new_camera(Request $request)
    {

        $request->validate([
            'region' => 'required|string',
            'camera' => 'required|string',
            'url' => 'required|url',

        ]);

        // $url = str_replace(array("http://", "https://"), "", $request->url);

        // $isStream = HelperData::isStreamGood($url);


        // if ($isStream != 200) {
        //     return redirect()->back()->withInput()->with('error', 'Invalid URL format');
        // }

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

        $currentDateTime = date('Y-m-d H:i:s');

        // Convert the formatted date to MongoDB BSON DateTime
        $dateTime = new UTCDateTime(strtotime($currentDateTime) * 1000);

        // Get the collection instance

        $dataToInsert = [
            'cameraname' => $request->camera,
            'stream_url' => $request->url,
            'status' => ($request->status) ? 1 : 0,
            'region_id' => new \MongoDB\BSON\ObjectID($request->region),
            'created_at' => $dateTime,
            'user_id' => auth()->user()->uuid,
            'is_virtial_wall' => 1,
            // Add other fields and their values
        ];

        // Insert the new document into the collection
        $insertResult = $collection->insertOne($dataToInsert);

        // Check if the insertion was successful
        if ($insertResult->getInsertedCount() > 0) {
            // Get the ID of the inserted document
            $insertedId = $insertResult->getInsertedId();
            $lastid =  json_encode($insertedId, false);
            $data = json_decode($lastid, true); // Decode the JSON string
            // Access the value associated with the key '$oid'
            $oidValue = $data['$oid'];
            // Now $oidValue contains the ObjectId value
            $stream_name = preg_replace("/[^a-zA-Z0-9]/", "", $request->camera);

            $params = [
                'stream_name' => $stream_name,
                'stream_url' => $request->url,
                'request_id' => "11111",
                'camera_id' => $oidValue,
                'region_id' => $request->region,
                'access_token' => '123456',
            ];



            // Encrypt user  information
            $enc = Encryption::encrypt(Auth()->user()->uuid);

            $encryptedData = $enc['encryptedData'];
            $iv =  $enc['iv'];

            $params['encrypt'] = $enc['encryptedData'];
            $params['iv'] = $enc['iv'];
            // echo json_encode($params); die();
            // Create VM API
            $response = ApiHelper::create_stream_vm($params, $encryptedData, $iv);

            $statusCode = $response->getStatusCode();

            if ($statusCode == 200) {
                $body  = $response->getBody()->getContents();
                $data = json_decode($body, true);

                if (isset($data['error'])) {
                    if ($data['error'] == true) {
                        session()->flash('error', $data['message']);
                    } else {


                        //==========================
                        // Insert stream settings
                        //==========================

                        $collection_camera_stream = $this->mongoDB->dataprocess->camera_stream_settings;
                        $data = [
                            'user_id' => auth()->user()->uuid,
                            'camera_id' => new \MongoDB\BSON\ObjectID($oidValue),
                            'extract_frame_time' => 10
                        ];
                        $result =  $this->mongoHelper->insertDataToCollection($data, $collection_camera_stream);

                        session()->flash("success", "Stream created successfully");
                        //  session()->flash('success',$data['message']);
                    }
                } else {
                    session()->flash('error', 'Invalid data set to create virtial machine');
                }
            } else {
                session()->flash('error', 'Invalid data set to create virtial machine');
            }
        } else {
            session()->flash("error", "Sorry try again");
        }

        return redirect(route('all.cameras.lists', $request->region));
    }

    public function findCamera($id)
    {

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

        $result = $collection->find(
            [
                '_id' => new \MongoDB\BSON\ObjectID($id)
            ]
        );
        $data = null;
        foreach ($result as $rs) {
            $data = $rs;
        }

        return view("add.edit_camera", compact("data"));
    }


    /*
      Update Camera
    */

    public function updateCamera(Request $request)
    {
        // echo json_encode($request->all());
        // die();


        $request->validate([
            'region' => 'required|string',
            'camera' => 'required|string',
            'url' => 'required|url',
            'id' => 'required|string',
        ]);

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

        // $isStream = HelperData::isStreamGood($request->url);

        // if ($isStream == 505) {
        //     session()->flash("error", "Invalid URL format");
        // }

        // if ($isStream != 200) {
        //     return redirect(route('all.cameras.lists'));
        // }

        // Convert the formatted date to MongoDB BSON DateTime

        // Get the collection instance

        $updateData = [
            '$set' => [
                'cameraname' => $request->camera,
                'stream_url' => $request->url,
                'status' => ($request->status) ? 1 : 0,
            ]
            // Add other fields and their values
        ];

        // Insert the new document into the collection
        $updateResult = $collection->updateOne(

            [
                '_id' => new \MongoDB\BSON\ObjectID($request->id),
                'user_id' => auth()->user()->uuid
            ],

            $updateData
        );

        // dd($updateResult);


        // Check if the insertion was successful
        if ($updateResult->getModifiedCount() > 0) {
            // Get the ID of the inserted document
            session()->flash("success", "Camera updated successfully");
        } else {
            session()->flash("error", "Sorry try again");
        }

        return redirect(route('all.cameras.lists', $request->region));
    }


    /*
      Delete Camera
    */

    public function deleteCamera($id)
    {
        $collection = $this->mongoDB->dataprocess->cameras;

        // Delete a single document by its _id
        $deleteResult = $collection->deleteOne([
            '_id' => new \MongoDB\BSON\ObjectID($id),
            'user_id' => auth()->user()->uuid
        ]);

        // Check if the deletion operation was successful
        // if ($deleteResult->getDeletedCount() > 0) {

        // } else {

        // }
        session()->flash("success", "Camera deleted successfully");
        return back();
    }

    public function camera_statistics($camera_id)
    {
        $collection = $this->mongoDB->dataprocess->steaming_info;
        $result = $collection->findOne([
            'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
            // 'user_id' => auth()->user()->uuid
        ]);

        return view('camera.statistics.index', compact('result'));
    }

    public function monitor_stream($camera_id)
    {

        $collection = $this->mongoDB->dataprocess->users_streams_vm;

        $result = $collection->findOne([
            'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
            //'user_id' => auth()->user()->uuid
        ]);

        if ($result) {

            $collection = $this->mongoDB->dataprocess->cameras;
            $collection_alarm_counts = $this->mongoDB->dataprocess->stream_alarm_counts;

            $stream = $collection->findOne([
                '_id' => new \MongoDB\BSON\ObjectID($camera_id),
                // 'user_id' => auth()->user()->uuid
            ]);

            $alarm_collections = $collection_alarm_counts->findOne([
                'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
                // 'user_id' => auth()->user()->uuid
            ]);

            $collection = $this->mongoDB->dataprocess->steaming_info;
            $steaming_info = $collection->findOne([
                'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
                // 'user_id' => auth()->user()->uuid
            ]);

            $cameraname = $stream['cameraname'];
            // Document found, return the _id
            $container = (string) $result['container_id']; // Convert BSON ObjectID to string
            return view("streams.view_stream", compact('result', 'container', 'cameraname', 'steaming_info', 'alarm_collections'));
        } else {
            // Document not found, handle the error
            // For example, return a message or throw an exception
            session()->flash('error', 'Stream not active yet');
            return back();
        }
        session()->flash('error', 'Stream not active yet');
        return back();
    }

    public function get_container_info(Request $request)
    {

        $request->validate([
            'container' => "required|string"
        ]);

        $response = ApiHelper::get_stream_vm([
            "request_id" => "11111",
            "container_id" =>  $request->container,
            "access_token" => "123456"
        ]);

        $statusCode = $response->getStatusCode();

        if ($statusCode == 200) {
            $body  = $response->getBody()->getContents();
            $data = json_decode($body, true);

            if (isset($data['error'])) {

                if ($data['error'] == true) {

                    return  response()->json([
                        'error' => true,
                        'error_code' => 1001,
                        'data' => "Sorry invalid data"
                    ]);
                } else {
                    return  response()->json([
                        'error' => false,
                        'data' => $data['data']['Status']
                    ]);
                    //  session()->flash('success',$data['message']);
                }
            } else {
                return  response()->json([
                    'error' => true,
                    'error_code' => 1002,
                    'data' => "Sorry invalid data"
                ]);
            }
        } else {
            return  response()->json([
                'error' => true,
                'error_code' => 1003,
                'data' => "Sorry invalid data"
            ]);
        }
    }

    public function camera_stream_setting($camera_id)
    {
        $collection = $this->mongoDB->dataprocess->cameras;
        $result = $collection->findOne([
            '_id' => new \MongoDB\BSON\ObjectID($camera_id),
            // 'user_id' => auth()->user()->uuid
        ]);

        if (!$result) {
            session()->flash("error", "Sorry invalid camera");
            return back();
        }

        $settings = $this->mongoDB->dataprocess->camera_stream_settings;
        $settings = $settings->findOne([
            'camera_id' => new \MongoDB\BSON\ObjectID($camera_id),
            // 'user_id' => auth()->user()->uuid
        ]);


        return view("camera.settings.stream_setting", compact('settings', 'camera_id'));
    }

    public function store_camera_stream_setting(Request $request)
    {

        $request->validate([
            'setting' => 'required|string',
            'camera' => 'required|string',
            'extract_frame_time' => 'required|numeric|min:0',
        ]);

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

        $result = $collection->findOne([
            '_id' => new \MongoDB\BSON\ObjectID($request->camera),
            // 'user_id' => auth()->user()->uuid
        ]);

        if (!$result) {
            session()->flash("error", "Sorry invalid camera");
            return back();
        }

        $updateData = [
            '$set' => [
                'extract_frame_time' => $request->extract_frame_time,
            ]
            // Add other fields and their values
        ];

        $settings = $this->mongoDB->dataprocess->camera_stream_settings;

        // Insert the new document into the collection
        $updateResult = $settings->updateOne(
            [
                '_id' => new \MongoDB\BSON\ObjectID($request->setting),
                'camera_id' => new \MongoDB\BSON\ObjectID($request->camera),
            ],
            $updateData
        );

        // Check if the insertion was successful
        if ($updateResult->getModifiedCount() > 0) {
            // Get the ID of the inserted document
            if ($updateResult->getModifiedCount() > 0) {


                $collection_vm = $this->mongoDB->dataprocess->users_streams_vm;

                $result = $collection_vm->findOne([
                    'camera_id' => new \MongoDB\BSON\ObjectID($request->camera),
                    'user_id' => auth()->user()->uuid
                ]);


                $response = ApiHelper::restart_streamming_server([
                    "request_id" => "11111",
                    "container_id" =>  $result['container_id'],
                    "access_token" => "123456",
                    "camera_id" => $request->camera,
                    "user_id" => Auth::user()->uuid
                ]);
                if ($response) {
                    session()->flash("success", "Stream settings updated successfully");
                } else {
                    session()->flash("error", "Sorry try again");
                }
            } else {
                session()->flash("error", "No modifications made 1001");
            }
        }else{
            session()->flash("error", "No modifications made 1002");

        }
        return back();
    }

    public function add_faces($camera_id){

    return view('add.add_faces', compact('camera_id'));
    }

    public function save_faces(request $request){

        // apply validation
        $request->validate([
            'camera_id' => 'required',
            'face_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
        ]);

        if ($request->hasFile('face_image')) {
            $file = $request->file('face_image');

            // get image base64
            $base64 = base64_encode(file_get_contents($file->getRealPath()));


            $mongoHelper = app(MongoHelper::class);
            $getCamera = $mongoHelper->findCamera($request->camera_id, Auth::user()->uuid);

                $cameraData = $getCamera[0];

                $cameraArray = $cameraData->getArrayCopy();

                if (isset($cameraArray['region_id'])) {
                    $region_id = $cameraArray['region_id'];

                    $data = [
                        'user_id' => Auth::user()->uuid,
                        'camera_id' => new \MongoDB\BSON\ObjectID($request->camera_id),
                        'region_id' => new \MongoDB\BSON\ObjectID($region_id),
                        'face_image' => $base64
                    ];


                    // insert into collection
                    $collection = $this->mongoDB->dataprocess->face_for_search;
                    $insertResult = $collection->insertOne($data);


                    if ($insertResult->getInsertedCount() > 0) {
                        return redirect()->back()->with('success', 'Face image uploaded successfully.');
                    } else {
                        return redirect()->back()->with('error', 'Failed to upload face image. Please try again.');
                    }

                } else {
                    dd('region_id not found in camera data');
                }
        }

        return redirect()->back()->with('error', 'Failed to upload face image.');
    }



    public function faces_all(){


        $collection = $this->mongoDB->dataprocess->face_for_search;

        $faces = $collection->find([], ['sort' => ['_id' => -1]])->toArray();
        return view("add.view_faces", compact('faces'));
    }


    public function delete_face($id){


        $collection = $this->mongoDB->dataprocess->face_for_search;
    $result = $collection->deleteOne(['_id' => new \MongoDB\BSON\ObjectId($id)]);


    if ($result->getDeletedCount() > 0) {
        return redirect()->back()->with('success', 'Face record deleted successfully');
    } else {
        return redirect()->back()->with('error', 'Face record not found or could not be deleted');
    }

    }
    }
