<?php

namespace App\Services;

use Exception;

class VsolManager
{
    private $host;
    private $communityString;
    private $port;
    private $objectIdentities;

    public function __construct($host, $communityString, $objectIdentities, $port = 161)
    {
        $this->host = $host;
        $this->communityString = $communityString;
        $this->port = $port;
        $this->objectIdentities = $objectIdentities;
    }

    public function getOltName()
    {
        $rawResult = $this->runCommandByOid($this->objectIdentities['oltName']);
        return $this->parseValueFromRawString(explode("\n", $rawResult)[0]);
    }

    public function getAllOnuInformation()
    {
        $macWithvlan = collect($this->getAllMacWithVlan())->keyBy('onuId');
        $interfaceWithOnuId = collect($this->getInterfaceNameWithOnuId())->keyBy('onuId');

        $onuLaserWithOnuId = collect($this->getAllOnuLaserWithOnuId())->mapWithKeys(function ($item) {
            // Normalize "1.25" to "1:25"
            $normalizedKey = str_replace('.', ':', $item['onuId']);
            return [$normalizedKey => $item];
        });

        $result = $macWithvlan->map(function ($item, $onuId) use ($interfaceWithOnuId, $onuLaserWithOnuId) {
            $interfaceData = $interfaceWithOnuId->get($onuId, []);
            $laserId = $interfaceData['laserID'] ?? null;
            $laserData = $laserId ? $onuLaserWithOnuId->get($laserId, []) : [];

            return array_merge($item, $interfaceData, $laserData);
        })->toArray();

        return $result;
    }

    private function parseValueFromRawString($rawString)
    {
        preg_match('/:\s(.+)$/', $rawString, $matches);
        return $matches[1] ?? null;
    }

    private function runCommandByOid($oid)
    {
        $snmpCommand = "snmpwalk -v 2c -c {$this->communityString} {$this->host}:{$this->port} $oid";
        exec($snmpCommand, $output, $returnVar);

        if ($returnVar !== 0) {
            throw new Exception("SNMP command failed");
        }

        return implode("\n", $output);
    }

    private function getAllMacWithVlan()
    {
        $rawResult = $this->runCommandByOid($this->objectIdentities['vlanMac']);
        $macs = explode("\n", $rawResult);

        return collect($macs)->map(function ($mac) {
            $macParts = explode("=", $mac);
            $oid = trim($macParts[0]);
            $macString = trim($macParts[1]);

            $oidParts = explode(".", $oid);
            $lastNumber = end($oidParts);

            preg_match('/Hex-STRING:\s+([0-9A-F ]+)/i', $macString, $matches);
            $macAddress = isset($matches[1]) ? str_replace(" ", ":", trim($matches[1])) : null;

            $vLan = $this->extractVlanFromOid($mac, $this->objectIdentities['vlanMac']);

            return [
                'onuId' => $lastNumber,
                'macAddress' => $macAddress,
                'vLan' => $vLan,
            ];
        })->toArray();
    }


    private function getInterfaceNameWithOnuId()
    {
        $rawResult = $this->runCommandByOid($this->objectIdentities['onuInterfaceName']);
        $splitted = explode("\n", $rawResult);

        return collect($splitted)->map(function ($row) {
            preg_match('/\\.([\\d]+)(?=\\s=\\s)/', $row, $matches);
            preg_match('/EPON0\/(\d+:\d+)/', $row, $laser);
            return [
                'interfaceName' => str_replace('"', '', $this->parseValueFromRawString($row)),
                'laserID' => $laser[1] ?? null,
                'onuId' => $matches[1] ?? null,
            ];
        })->toArray();
    }


    private function getAllOnuLaserWithOnuId()
    {
        $rawResult = $this->runCommandByOid($this->objectIdentities['onuLaser']);
        $splitted = explode("\n", $rawResult);
        //dd($splitted);
        return collect($splitted)->map(function ($row) {
            preg_match('/\.(\d+\.\d+) =/', $row, $matches);
            preg_match('/\((-?\d+\.\d+) dBm\)/', $row, $output);
            return [
                'onuLaser' => $output[1] ?? null,
                'onuId' => $matches[1] ?? null,
            ];
        })->toArray();
    }

    private function extractVlanFromOid($row, $baseOid)
    {
        return explode('.', str_replace($baseOid, '', $row))[1] ?? null;
    }
}
