<?php

namespace App\Http\Controllers\Map;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

use App\Models\map\Port;
use App\Models\map\Fiber;
use App\Models\map\Onu;
use App\Models\map\Splitter;
use App\Models\map\SplitterOut;
use App\Models\Clientsinfo;


class ConnectivityController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

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

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

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

    public function devicePortToDevicePort(Request $request)
    {

        $portB = Port::with("device")->find($request->component_b["pointId"]);

        if (!$request->isFromCable) {
            $portA = Port::with("device")->find($request->component_a["pointId"]);
            // check if portA and portB are in the same device
            if ($portA->device_id == $portB->device_id) {
                return response()->json([
                    "message" => "Ports are in the same device",
                ], 400);
            }

            $portA->connected_component_id = $portB->id;
            $portA->connected_component_type = $portB->type;
            $portB->connected_component_id = $portA->id;
            $portB->connected_component_type = $portA->type;
            $portA->save();
        }

        if ($request->fiber != null) {
            $currentFiber = Fiber::find($request->fiber);
            $portB->fiber_id = $currentFiber->id;
            $portB->cable_id = $currentFiber->cable_id;
        }


        $portB->save();

        return response()->json([
            "message" => "Ports connected successfully",
        ], 200);
    }

    public function splitterToSplitter(Request $request)
    {
        $splitterOut = SplitterOut::with("splitter")->find($request->component_a["pointId"]);
        $splitterIn = Splitter::find($request->component_b["id"]);

        // Check if splitterOut is already connected
        if ($splitterOut->connected_component_id != null) {
            return response()->json([
                "message" => "SplitterOut is already connected",
            ], 400);
        }

        // Check if splitterIn is already connected
        if ($splitterIn->connected_component_id != null) {
            return response()->json([
                "message" => "SplitterIn is already connected",
            ], 400);
        }

        $splitterOut->connected_component_id = $splitterIn->id;
        $splitterOut->connected_component_type = $splitterIn->type;
        $splitterOut->splitter->used++;

        $splitterIn->connected_component_id = $splitterOut->id;
        $splitterIn->connected_component_type = $splitterOut->type;
        $splitterIn->port_id = $splitterOut->splitter->port_id;

        $splitterOut->save();
        $splitterOut->splitter->save();
        $splitterIn->save();

        return response()->json([
            "message" =>  "Splitter connected successfully",
        ], 201);
    }


    public function switchPortToOnu(Request $request)
    {
        $port = Port::find($request->component_a["pointId"]);
        $onu = Onu::find($request->component_b["id"]);

        // Check if the port is already connected
        if ($port->connected_component_id != null) {
            return response()->json([
                "message" => "Port is already connected",
            ], 400);
        }

        // Check if the onu is already connected
        if ($onu->optical_connected_component_id != null) {
            return response()->json([
                "message" => "Onu is already connected",
            ], 400);
        }

        $port->connected_component_type = $onu->type;
        $port->connected_component_id = $onu->id;

        $onu->optical_connected_component_type = $port->type;
        $onu->optical_connected_component_id = $port->id;

        $port->save();
        $onu->save();

        return response()->json([
            "message" =>  "Switch Port connected to Onu",
        ], 201);
    }

    public function onuToSwitchPort(Request $request)
    {
        $onu = Onu::find($request->component_a["id"]);
        $port = Port::find($request->component_b["pointId"]);

        // Check if the onu is already connected
        if ($onu->lan_connected_component_id != null) {
            return response()->json([
                "message" => "Onu is already connected",
            ], 400);
        }

        // Check if the port is already connected
        if ($port->connected_component_id != null) {
            return response()->json([
                "message" => "Port is already connected",
            ], 400);
        }

        $onu->lan_connected_component_type = $port->type;
        $onu->lan_connected_component_id = $port->id;

        $port->connected_component_type  = $onu->type;
        $port->connected_component_id = $onu->id;

        $port->save();
        $onu->save();

        return response()->json([
            "message" => "Onu is connected with switch port."
        ], 201);
    }

    public function splitterToOnu(Request $request)
    {
        $splitterOut = SplitterOut::with("splitter")->find($request->component_a["pointId"]);
        $onu = Onu::find($request->component_b["id"]);

        // Check if splitterOut is already connected
        if ($splitterOut->connected_component_id != null) {
            return response()->json([
                "message" => "SplitterOut is already connected",
            ], 400);
        }

        // Check if onu is already connected
        if ($onu->optical_connected_component_id != null) {
            return response()->json([
                "message" => "Onu is already connected",
            ], 400);
        }

        $splitterOut->connected_component_id = $onu->id;
        $splitterOut->connected_component_type = $onu->type;
        $splitterOut->splitter->used++;

        $onu->optical_connected_component_type = $splitterOut->type;
        $onu->optical_connected_component_id = $splitterOut->id;

        $splitterOut->save();
        $splitterOut->splitter->save();
        $onu->save();

        return response()->json([
            "message" => "Splitter is connected with Onu TT",
        ], 201);
    }

    public function devicePortToSplitter(Request $request)
    {
        $port = Port::with("device")->find($request->component_a["pointId"]);
        $splitter = Splitter::find($request->component_b["id"]);

        // Check if the port is already connected
        if ($port->connected_component_id != null) {
            return response()->json([
                "message" => "Port is already connected",
            ], 400);
        }

        // Check if the splitter is already connected
        if ($splitter->connected_component_id != null) {
            return response()->json([
                "message" => "Splitter is already connected",
            ], 400);
        }

        $port->connected_component_id = $splitter->id;
        $port->connected_component_type = $splitter->type;

        $splitter->connected_component_type = $port->type;
        $splitter->connected_component_id = $port->id;
        $splitter->port_id = $port->id;

        $splitter->save();
        $port->save();

        return response()->json([
            "message" => "Device port connected to splitter successfully",
        ], 200);
    }

    public function componentToClient(Request $request)
    {
        $component = null;
        $clientInfo = Clientsinfo::find($request->component_b["id"]);

        switch ($request->component_a["type"]) {
            case "port":
                $component = Port::find($request->component_a["pointId"]);
                break;
            case "splitter":
                $component = SplitterOut::with("splitter")->find($request->component_a["pointId"]);
                break;
            default:
                throw new \ErrorException('Component is not valid Type.');
        }

        // Check if the component is already connected
        if ($component->connected_component_id != null) {
            return response()->json([
                "message" => "Component is already connected",
            ], 400);
        }

        // Check if the client is already connected
        if ($clientInfo->connected_component_id != null) {
            return response()->json([
                "message" => "Client is already connected",
            ], 400);
        }

        $component->connected_component_type = $clientInfo->type;
        $component->connected_component_id = $clientInfo->id;

        $clientInfo->connected_component_type = $component->type;
        $clientInfo->connected_component_id = $component->id;

        if ($request->component_a["type"] == "splitter") {
            $component->splitter->used++;
            $component->splitter->save();
        }

        $component->save();
        $clientInfo->save();

        return response()->json([
            "message" => "Component connected to Client successfully",
        ], 200);
    }

    public function connectCableToComponent(Request $request)
    {
        $fiber = Fiber::find($request->fiber);

        if (!$fiber) {
            return response()->json([
                "error" => "Fiber not found",
            ], 404);
        }

        $componentBIdType = $request->component_b["type"];
        $componentBId = $request->component_b["id"];
        $componentBPointId = $request->component_b["pointId"];

        if ($componentBIdType == "port") {
            $component = Port::find($componentBPointId);
        } else if ($componentBIdType == "splitter") {
            if ($componentBPointId) {
                $component = SplitterOut::with("splitter")->find($componentBPointId);
            } else {
                $component = Splitter::find($componentBId);
            }
        } else if ($componentBIdType == 'onu') {
            $component = Onu::find($componentBId);
        } else {
            return response()->json([
                "error" => "Component type is not valid.",
            ], 404);
        }

        if (!$component) {
            return response()->json([
                "error" => "Component not found",
            ], 404);
        }

        if ($component->fiber_id !== null && $component->fiber_id != $fiber->id) {
            return response()->json([
                "error" => "Component is already connected to another cable",
            ], 400);
        }

        if ($request->stream === "start" && $fiber->parent_component_id && $fiber->parent_component_id != $component->id) {
            return response()->json([
                "error" => "Cable is already connected to another component",
            ], 400);
        }

        if ($request->stream == "end" && $fiber->child_component_id && $fiber->child_component_id != $component->id) {
            return response()->json([
                "error" => "Cable is already connected to another component",
            ], 400);
        }

        $component->fiber_id = $fiber->id;
        $component->cable_id = $fiber->cable_id;
        $component->save();

        if ($request->stream === "start") {
            $fiber->parent_component_type = $component->type;
            $fiber->parent_component_id = $component->id;
        } else if ($request->stream === "end") {
            $fiber->child_component_type = $component->type;
            $fiber->child_component_id = $component->id;
        }

        $fiber->save();

        return response()->json([
            "message" => "Cable connected to component successfully",
        ], 200);
    }

    public function connect(Request $request)
    {

        $componentAType = $request->component_a['type'];
        $componentBType = $request->component_b["type"];
        if ($request->isFromCable) {
            return $this->connectCableToComponent($request);
        } else {
            if (
                $componentAType == "port"
                && $componentBType == "port"
            ) {
                return $this->devicePortToDevicePort($request);
            } else if (
                $componentAType == "splitter"
                && $componentBType == "splitter"
            ) {
                return $this->splitterToSplitter($request);
            } else if (
                $componentAType == "port"
                && $componentBType == "splitter"
            ) {
                return $this->devicePortToSplitter($request);
            } else if (
                $componentAType == "port"
                && $componentBType == "onu"
            ) {
                return $this->switchPortToOnu($request);
            } else if (
                $componentAType == "onu"
                && $componentBType == "port"
            ) {
                return $this->onuToSwitchPort($request);
            } else if (
                $componentAType == "splitter"
                && $componentBType == "onu"
            ) {
                return $this->splitterToOnu($request);
            } else if ($componentBType == "client") {
                return $this->componentToClient($request);
            } else {
                return response()->json([
                    "message" => "$componentAType can't connected to $componentBType",
                ], 400);
            }
        }
    }
}
