<?php

namespace App\Http\Controllers\Map;

use App\Http\Controllers\Controller;
use App\Models\map\Device;
use App\Models\map\Port;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class DeviceController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return Device::with("ports")->get();
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            "name" => "required",
            "manufactures" => "required",
            "model" => "required",
            "remarks" => "nullable",
            "cluster_id" => "required",
            "indoor" => "nullable|boolean",
            "coordinates" => "nullable",
            "ports" => "required",
            "total_ports" => "required|integer",
        ]);

        // create device
        $device = Device::create([
            "name" => $request->name,
            "manufactures" => $request->manufactures,
            "model" => $request->model,
            "serial_number" => $request->serial_number,
            "remarks" => $request->remarks,
            "cluster_id" => $request->cluster_id,
            "indoor" => $request->indoor == null ? true : $request->indoor,
            "coordinates" => $request->coordinates,
            "total_ports" => $request->total_ports,
            "type" => "device",
        ]);

        // create ports
        foreach ($request->ports as $port) {
            $device->ports()->create([
                "port_number" => $port["port_number"],
                "label" => $port["label"],
                "port_type" => $port["type"],
                "port_stream" => $port["port_stream"],
            ]);
        }

        return $device->load("ports");
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\map\Device  $device
     * @return \Illuminate\Http\Response
     */
    public function show(Device $device)
    {
        return $device->load("ports");
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\map\Device  $device
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Device $device)
    {
        $this->validate($request, [
            "name" => "required",
            "manufactures" => "required",
            "model" => "required",
            "remarks" => "nullable",
        ]);

        $device->name = $request->name;
        $device->manufactures = $request->manufactures;
        $device->model = $request->model;
        $device->serial_number = $request->serial_number;
        $device->remarks = $request->remarks;

        $device->save();

        return $this->deviceDetail($device);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\map\Device  $device
     * @return \Illuminate\Http\Response
     */
    public function destroy($device_id)
    {
        $device = $this->deviceDetail(Device::find($device_id));
        if (!$device) {
            return response()->json([
                "message" => "Device not found"
            ], 404);
        }

        DB::beginTransaction();
        try {
            foreach ($device->ports as $port) {
                if ($port->fiber_id || $port->connected_component_id) {
                    throw new \Exception("Port is connected to a component.");
                }
                $port->delete();
            }

            $device->delete();
            DB::commit();
        } catch (\Throwable $th) {
            DB::rollBack();
            return response()->json([
                "message" => $th->getMessage()
            ], 400);
        }
        return response()->json([
            "message" => "Device deleted successfully"
        ], 200);
    }

    public function deviceDetail(Device $device)
    {
        $relations = [
            "ports.connectedComponent.device:name,id,manufactures,model,cluster_id,type",
            "ports.connectedComponent.client:userid,password,clients_status,id",
            "ports.fiber:fiber_number,id,cable_id",
            "ports.fiber.cable:name,id,type",
        ];

        return $device->load($relations);
    }

    public function disconnectPort($port_id)
    {
        $port = Port::with("connectedComponent", "fiber")->find($port_id);

        if ($port->fiber_id) {
            $fiber = $port->fiber;
            if ($fiber->parent_component_type === $port->type && $fiber->parent_component_id === $port->id) {
                $fiber->parent_component_type = null;
                $fiber->parent_component_id = null;
            } else if ($fiber->child_component_type === $port->type && $fiber->child_component_id === $port->id) {
                $fiber->child_component_type = null;
                $fiber->child_component_id = null;
            } else {
                return response()->json([
                    "message" => "Fiber is not connected to this port"
                ], 400);
            }

            $fiber->save();
        } else if (
            in_array($port->connected_component_type, ["splitter", "splitter_out", "port", "client"]) && $port->connected_component_id
        ) {
            $connectedComponent = $port->connectedComponent;
            $connectedComponent->connected_component_type = null;
            $connectedComponent->connected_component_id = null;
            $connectedComponent->save();
        } else if ($port->connected_component_type === "onu") {
            if ($port->connectedComponent->lan_connected_component_type === $port->type && $port->connectedComponent->lan_connected_component_id === $port->id) {
                $port->connectedComponent->lan_connected_component_type = null;
                $port->connectedComponent->lan_connected_component_id = null;
            } else if ($port->connectedComponent->optical_connected_component_type === $port->type && $port->connectedComponent->optical_connected_component_id === $port->id) {
                $port->connectedComponent->optical_connected_component_type = null;
                $port->connectedComponent->optical_connected_component_id = null;
            } else {
                return response()->json([
                    "message" => "Onu is not connected to this port"
                ], 400);
            }
            $port->connectedComponent->save();
        } else {
            return response()->json([
                "message" => "Port is not connected to any component"
            ], 400);
        }


        $port->connected_component_type = null;
        $port->connected_component_id = null;
        $port->fiber_id = null;
        $port->cable_id = null;
        $port->save();

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

    public function updatePortDetail(Port $port, Request $request)
    {
        $port->label = $request->label;
        $port->port_type = $request->port_type;
        $port->port_stream = $request->port_stream;
        $port->save();

        return $port;
    }
}
