<?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',
            'created_by'    => auth()->user()->id
        ]);



        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'
            ]
        );

        $nas = Nas::find($id);

        // 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;
        // }
        if ($request->port) {
            $port_length = count($request->port);
            $data = [];

            // Get existing data to preserve IDs
            $existing_data = [];
            if ($nas->ip_block) {
                $existing_data = json_decode($nas->ip_block, true);
            }

            for ($i = 0; $i < $port_length; $i++) {
                // Use existing ID if available, otherwise generate new
                $id = isset($existing_data[$i]) ? $existing_data[$i]['id'] : count($existing_data) + $i;

                $data[] = [
                    'id' => $id,
                    '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->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 = [];
        $mk = null;

        // check if host is reachable
        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: " . $th->getMessage(),
                "status" => "danger"
            ]);
            return view('mikrotik.testMikroTikConnection', [
                "result" => $resultOfTest,
                "mikrotik" => $mikrotick_info
            ]);
        }

        // creating secret
        try {
            if (!$mk->getUserOrNull("yetfixDummy")) {
                $new_data = [
                    "username" => "yetfixDummy",
                    "password" => "12345678",
                    "service" => "pppoe",
                    "profile" => "default",
                    "comment" => "This is a dummy secret. Created for testing mk connectivity by YetFix.",
                    "disabled" => "no"
                ];
                $mk->createSecret($new_data);
                array_push($resultOfTest, [
                    "message" => "Secret created successfully.",
                    "status" => "success"
                ]);
            } else {
                array_push($resultOfTest, [
                    "message" => "yetfixDummy secret already exists on Mk.",
                    "status" => "warning"
                ]);
            }
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Error creating secret: " . $th->getMessage(),
                "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" => "Secret updated successfully.",
                    "status" => "success"
                ]);
            } else {
                array_push($resultOfTest, [
                    "message" => "Updated secret name UPdatedYetfix already exists in mk.",
                    "status" => "warning"
                ]);
            }
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Error updating secret: " . $th->getMessage(),
                "status" => "danger"
            ]);
        }

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

        // enabling secret
        try {
            $mk->enableSecret("UPdatedYetfix");
            array_push($resultOfTest, [
                "message" => "Secret enabled successfully.",
                "status" => "success"
            ]);
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Error enabling secret: " . $th->getMessage(),
                "status" => "danger"
            ]);
        }

        // deleting secret
        try {
            $mk->deleteSecret("UPdatedYetfix");
            array_push($resultOfTest, [
                "message" => "Secret deleted successfully.",
                "status" => "success"
            ]);
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Error deleting secret: " . $th->getMessage(),
                "status" => "danger"
            ]);
        }

        // active connection test
        try {
            $activeConnections = $mk->getActiveConnection();
            array_push($resultOfTest, [
                "message" => "Active connections retrieved successfully.",
                "status" => "success"
            ]);

            if (sizeof($activeConnections) > 0) {
                $activeSecret = $activeConnections[0];
                for ($i = 0; $i < 3; $i++) {
                    $mk->getSpeed($activeSecret["name"]);
                }
                array_push($resultOfTest, [
                    "message" => "Speed test completed successfully.",
                    "status" => "success"
                ]);

                $mk->disconnectSecret($activeSecret["name"]);
                array_push($resultOfTest, [
                    "message" => "Active connection disconnected successfully.",
                    "status" => "success"
                ]);
            } else {
                array_push($resultOfTest, [
                    "message" => "No active connections found for speed test.",
                    "status" => "warning"
                ]);
            }
        } catch (\Throwable $th) {
            array_push($resultOfTest, [
                "message" => "Error testing active connection: " . $th->getMessage(),
                "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)->orderBy('created_at', 'desc')->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 == 'limitedyetfix@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);
        }
    }
}
