<?php

namespace App\Http\Controllers;

use App\Classes\MikrotikService\SyncWithMk;
use App\Classes\MikrotikService\Mikrotik as ClassesMikrotik;
use App\Models\LogHistory;
use App\Models\MikcrotikClientList;
// use App\Models\Mikrotik;
use App\Models\MikrotikEditLog;
use Illuminate\Http\Request;
use App\Models\Nas;
use App\Models\Packages;
use App\Models\Reseller;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Database\Capsule\Manager;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use \RouterOS\Query;
use App\Classes\EditLogHistory;
use App\Models\Client;
use App\Models\Pop;
use App\Models\NasProfile;
use App\Classes\MikrotikService\Mikrotik;
use Exception;

class MikrotikController extends Controller
{

    public function __construct()
    {
        $this->middleware('permission:mikrotik_index|mikrotik_create|mikrotik_edit|mikrotik_destroy', ['only' => ['index', 'show']]);
        $this->middleware('permission:mikrotik_create', ['only' => ['create', 'store']]);
        $this->middleware('permission:mikrotik_edit', ['only' => ['edit', 'update']]);
        $this->middleware('permission:mikrotik_destroy', ['only' => ['destroy']]);
    }
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $allNas = Nas::paginate(500);
        $page_title = 'Mikrotik';

        //dd($allNas );
        return view('mikrotik.index', [
            'page_title' => $page_title,
            'nas' => $allNas

        ]);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('mikrotik.create', [
            'page_title' => 'Add New Mikrotik Router'
        ]);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {

        $this->validate(
            $request,
            [
                'shortname' => 'required',
                'nasname' => 'required|unique:nas,nasname',
                // 'secret' => 'required',
                'description' => 'required'
            ],
            [
                'nasname.unique' => 'The Mikrotik Ip has already been taken.',
                'nasname.required' => 'The Mikrotik Ip field is Required',
                'shortname.required' => 'Mikrotik Name field Is Required'
            ]
        );

        if ($request->port) {
            $port_length = count($request->port);
            $data = [];
            for ($i = 0; $i < $port_length; $i++) {
                $data[] = [
                    'id' => $i,
                    'port' => $request->port[$i],
                    'ip_block' => $request->ip_block[$i]
                ];
            }
            $ipBlock = json_encode($data);
        } else {
            $ipBlock = null;
        }

        // dd($request->all());

        $result = Nas::create([
            'nasname'       => $request->nasname,
            'shortname'     => $request->shortname,
            'secret'        => $request->secret,
            'mikrotick_user'        => $request->mickrotik_user_name,
            'mikrotick_user_password'        => $request->mickrotik_user_password,
            'mikrotick_port'        => $request->mickrotik_port,
            'description'   => $request->description,
            'ip_block'      => $ipBlock,
            'type'          => 'other'
        ]);



        exec('/usr/bin/sudo /etc/init.d/freeradius restart');

        $request->session()->flash('success_message', 'Mikrotik Added successfully');
        return redirect()->route('mikrotiks.index');
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\Mikrotik  $mikrotik
     * @return \Illuminate\Http\Response
     */
    public function show(Nas $nas)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\Mikrotik  $mikrotik
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {

        $Nas = Nas::find($id);
        $services = null;
        if (auth()->user()->id == 1 && checkAPI()) {
            try {
                $mk = new ClassesMikrotik($Nas->nasname, $Nas->mikrotick_user, $Nas->mikrotick_user_password, $Nas->mikrotick_port ? (int)$Nas->mikrotick_port : 8728);
                $services = $mk->getServices();
            } catch (\Throwable $th) {
                //throw $th;
            }
        }

        $page_title = 'Mikrotik Router Update';
        return view('mikrotik.update', [
            'page_title' => $page_title,
            'nas' => $Nas,
            "mkServices" => json_encode($services)
        ]);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Mikrotik  $mikrotik
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate(
            $request,
            [
                'shortname' => 'required',
                'nasname' => 'required|unique:nas,nasname,' . $id,
                // 'secret' => 'required',
                'description' => 'required'
            ],
            [
                'nasname.unique' => 'The Mikrotik Ip has already been taken.',
                'nasname.required' => 'The Mikrotik Ip field is Required',
                'shortname.required' => 'Mikrotik Name field Is Required'
            ]
        );

        if ($request->port) {
            $port_length = count($request->port);
            $data = [];
            for ($i = 0; $i < $port_length; $i++) {
                $data[] = [
                    'id' => $i,
                    'port' => $request->port[$i],
                    'ip_block' => $request->ip_block[$i]
                ];
            }
            $ipBlock = json_encode($data);
        } else {
            $ipBlock = null;
        }

        $type = 'Mikrotik';
        $old_info = Nas::where('id', $id)->first();

        $nas = Nas::find($id);
        $nas->nasname = $request->nasname;
        $nas->shortname = $request->shortname;
        $nas->secret = $request->secret;
        $nas->description = $request->description;
        $nas->mikrotick_user = $request->mickrotik_user_name;
        $nas->mikrotick_user_password = $request->mickrotik_user_password;
        $nas->mikrotick_port = $request->mickrotik_port;
        $nas->ip_block = $ipBlock;
        $nas->update();

        // Nas::where('id',$id)->update([
        //     'nasname'      => $request->nasname,
        //     'shortname'    => $request->shortname,
        //     'secret'       => $request->secret,
        //     'description'  => $request->description
        // ]);

        $new_info = Nas::find($nas->id);
        (new EditLogHistory)->editLogSave($nas, $type, $old_info, $new_info);


        exec('/usr/bin/sudo /etc/init.d/freeradius restart');

        $request->session()->flash('success_message', 'Mikrotik Update successfull');

        return redirect()->route('mikrotiks.index');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\Mikrotik  $mikrotik
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {

        $nas = Nas::find($id);
        $pop = Pop::where('nas_id', $nas->id)->first();
        if ($pop) {
            Toastr::error('Mikrotik is used in Pop. Cannot delete.', 'Success');
            return redirect()->back();
        } else {
            $nas->delete();
            Toastr::success('Mikrotik Delete successfull', 'Success');
            return redirect()->back();
        }
    }

    public function mikrotiksSync(Request $request)
    {

        $data = [

            'mikrotiks' => Nas::all(),
            'client_lists' => MikcrotikClientList::get(),
            'resellers' => Reseller::all(),
            'billing_cycles' => config('app.billing_cycle'),
        ];
        return view('mikrotik.sync', $data);
    }

    public function mikrotiksProfileSync()
    {
        $data = [
            'mikrotiks' => Nas::all(),
            'list' => NasProfile::get(),
        ];

        return view('mikrotik.profileSync', $data);
    }

    public function mikrotiksSyncProfile(Request $request)
    {
        $mikrotick_info = Nas::where('id', $request->mikrotik)->first();
        if (!$mikrotick_info) {
            return response("MikroTik Not Found ", 404);
        }
        $mk = new Mikrotik($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728);
        $responseProfile = $mk->getProfiles();

        foreach ($responseProfile as $key => $value) {
            $profile_list = NasProfile::where('profile_name', $value['name'])->first();
            if ($profile_list == null) {
                $profile = new NasProfile();
                $profile->profile_name = $value['name'];
                $profile->mk_info = $mikrotick_info->nasname;
                $profile->save();
            }
        }

        return view('mikrotik.profileSync', [
            'list' => NasProfile::get(),
            'mikrotiks' => Nas::all(),
        ]);
    }

    public  function syncClientList()
    {
        $data = [

            'client_lists' => MikcrotikClientList::paginate(10),
        ];
        return view('mikrotik.syncClient', $data);
    }

    public function deleteFromSyncList(Request $request)
    {
        MikcrotikClientList::where('username', $request->userName)->delete();
        return "success";
    }

    private function isHostReachable($host)
    {
        exec("ping -c 1 -W 5 " . escapeshellarg($host), $output, $returnVal);
        if ($returnVal == 0) {
            return true;
        } else {
            return false;
        }
    }

    private function isPortOpen($host, $port, $timeout = 5)
    {
        $starttime = microtime(true); // Start measuring time
        $socket = @fsockopen($host, $port, $errno, $errstr, $timeout);
        $stoptime = microtime(true);  // Stop measuring time
        $status = 0; // Default status

        if (!$socket) {
            $status = false;  // Unable to connect
        } else {
            fclose($socket);
            $status = ($stoptime - $starttime) * 1000;
            $status = floor($status);
        }

        return $status;
    }

    public function testMikrotikConnection(Request $request, $id)
    {
        $mikrotick_info = Nas::find($id);
        if (!$mikrotick_info) {
            $request->session()->flash('error_message', 'Mikrotik not Found.');
            return Redirect()->back();
        }

        $resultOfTest = [];

        // all the tests

        // check if host is reachable, if we can ping it.
        if ($this->isHostReachable($mikrotick_info->nasname)) {
            array_push($resultOfTest, [
                "message" => "Mikrotik Host is reachable, ping successful.",
                "status" => "success"
            ]);
        } else {
            array_push($resultOfTest, [
                "message" => "Mikrotik Host is not reachable, ping failed.",
                "status" => "danger"
            ]);
        }

        // check if port open
        if ($this->isPortOpen($mikrotick_info->nasname, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728)) {
            array_push($resultOfTest, [
                "message" => "Mikrotik Port is open and accessible.",
                "status" => "success"
            ]);
        } else {
            array_push($resultOfTest, [
                "message" => "Mikrotik Port close or incorrect.",
                "status" => "danger"
            ]);
        }
        // ============ mikrotik Connection Test ============
        try {
            $mk = new ClassesMikrotik($mikrotick_info->nasname, $mikrotick_info->mikrotick_user, $mikrotick_info->mikrotick_user_password, $mikrotick_info->mikrotick_port ? (int)$mikrotick_info->mikrotick_port : 8728);
            array_push($resultOfTest, [
                "message" => "Mikrotik Login successful.",
                "status" => "success"
            ]);
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Mikrotik Login failed. Please Check Mikrotik credentials.",
                "status" => "danger"
            ]);
        }

        //  ============ creating secret ============
        try {
            if (!$mk->getUserOrNull("yetfixDummy")) {
                $new_data = [];
                $new_data["username"] = "yetfixDummy";
                $new_data["password"] = "12345678";
                $new_data["service"] = "pppoe";
                $new_data["profile"] = "default";
                $new_data["comment"] = "This is a dummy secret. Created for testing mk connectivity by YetFix.";
                $new_data["disabled"] = "no";

                $mk->createSecret($new_data);

                array_push($resultOfTest, [
                    "message" => "Secret created succesfully.",
                    "status" => "success"
                ]);
            } else {
                array_push($resultOfTest, [
                    "message" => "yetfixDummy secret already exist on Mk.",
                    "status" => "warning"
                ]);
            }
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Something went wrong while creating secret",
                "status" => "danger"
            ]);
        }

        //  ============ Updating Secret ============

        try {
            if (!$mk->getUserOrNull("UPdatedYetfix")) {
                $mk->updateSecret("yetfixDummy", [
                    'username' => "UPdatedYetfix",
                    "password" => "GGYEtflix",
                    "service" => "pppoe",
                    "profile" => "default",
                    "disabled" => "no",
                    "comment" => "This is a dummy secret. Created for testing mk secret update by YetFix."
                ]);

                array_push($resultOfTest, [
                    "message" => "Updating secret successfully.",
                    "status" => "success"
                ]);
            } else {
                array_push($resultOfTest, [
                    "message" => "updated secret name UPdatedYetfix already exist in mk.",
                    "status" => "warning"
                ]);
            }
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Updating secret fail. please check on mikrotik.",
                "status" => "danger"
            ]);
        }


        //  ============ disabling Secret ============
        try {
            $mk->disableSecret("UPdatedYetfix");
            array_push($resultOfTest, [
                "message" => "Disabled secret successfully.",
                "status" => "success"
            ]);
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Disabled secret fail.",
                "status" => "danger"
            ]);
        }

        //  ============ enableing Secret ============
        try {
            $mk->enableSecret("UPdatedYetfix");
            array_push($resultOfTest, [
                "message" => "Enabled secret successfully.",
                "status" => "success"
            ]);
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Enabled secret fail.",
                "status" => "danger"
            ]);
        }
        //  ============ deleting Secret ============
        try {
            $mk->deleteSecret("UPdatedYetfix");
            array_push($resultOfTest, [
                "message" => "Deleted secret successfully.",
                "status" => "success"
            ]);
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Something went wrong while deleting secret.",
                "status" => "danger"
            ]);
        }


        //  ============ active connection Test ============
        try {
            $activeConnections = $mk->getActiveConnection();
            array_push($resultOfTest, [
                "message" => "Active connection acknowledged successfully.",
                "status" => "success"
            ]);
            // dd($activeConnections);
            if (sizeof($activeConnections) > 0) {
                $activeSecret = $activeConnections[0];
                for ($i = 0; $i < 3; $i++) {
                    $mk->getSpeed($activeSecret["name"]);
                }
                array_push($resultOfTest, [
                    "message" => "Speed Test successfully acknowledged.",
                    "status" => "success"
                ]);

                $mk->disconnectSecret($activeSecret["name"]);
                array_push($resultOfTest, [
                    "message" => "Active connection disconnected successfully.",
                    "status" => "success"
                ]);
            } else {
                array_push($resultOfTest, [
                    "message" => "No active Connection found for speed test.",
                    "status" => "warning"
                ]);
            }
        } catch (\Throwable $th) {
            // dd($th);
            array_push($resultOfTest, [
                "message" => "Something went wrong while checking active connection and speed.",
                "status" => "danger"
            ]);
        }

        return view('mikrotik.testMikroTikConnection',  [
            "result" => $resultOfTest,
            "mikrotik" => $mikrotick_info
        ]);
    }

    public function allCustomerToMikrotik()
    {
        $sync = (new SyncWithMk)->syncAllSecretsToMk();
    }

    public function deleteAllFromSyncList()
    {
        MikcrotikClientList::truncate();
        return "success";
    }

    public function deleteAllProfileFromSyncList()
    {
        NasProfile::truncate();
        return "success";
    }

    public function editLogHistory($id, $type)
    {
        $item = LogHistory::with('nas', 'pop', 'user')->where('log_type', $type)->where('log_id', $id)->get();

        return view('mikrotik.editLog', [
            'list' => $item,
            'type' => $type
        ]);
    }



    // get api from mikrotik


    public function getMikrotik($id, $email)
    {
        $Nas = Nas::find($id);
        // $services = null;
        // if ($email == 'rokibulhasan.356@gmail.com' && checkAPI()) {
        //     try {
        //         $mk = new ClassesMikrotik($Nas->nasname, $Nas->mikrotick_user, $Nas->mikrotick_user_password, $Nas->mikrotick_port ? (int)$Nas->mikrotick_port : 8728);
        //         $services = $mk->getServices();
        //     } catch (\Throwable $th) {
        //         //throw $th;
        //     }
        // }

        return response()->json([
            "nas" => $Nas,
            // "services" => $services
        ]);
    }
    public function getMikrotikSecret($mkId)
    {
        $Nas = Nas::find($mkId);
        $mk = new ClassesMikrotik($Nas->nasname, $Nas->mikrotick_user, $Nas->mikrotick_user_password, $Nas->mikrotick_port ? (int)$Nas->mikrotick_port : 8728);
        $secrets = $mk->getSecret();
        return view('mikrotik.secrets', [
            'secrets' => $secrets,
            'nas' => $Nas
        ]);
    }

    public function savePackageFromSyncList(Request $request)
    {
        $this->validate($request, [
            'package_name'  => checkAPI() ? 'required|unique:packages,package_name' : '',
            'package_rate'  => 'required',
            'pool_name'     => checkAPI() ? '' : 'required',
        ]);

        try {
            if (Packages::where('package_name', $request->package_name)->first()) {
                return response("প্যাকেজ আগে থেকেই আছে", 404);
            }
            if (checkAPI()) {
                $package = new Packages();
                $package->package_name = trim($request->package_name);
                $package->profile_name= trim($request->profile_name);
                $package->package_rate= trim($request->package_rate);
                $package->package_bandwidth= trim($request->package_bandwidth ?? 0);
                $package->btrc_package_price= trim($request->btrc_package_price ?? 0);
                $package->save();

                NasProfile::where('profile_name', $request->profile_name)->delete();
            }
            return response("Success", 200);
        } catch (Exception $e) {
            return response("Error", 404);
        }
    }
}
