<?php

namespace App\Console\Commands;

use App\Models\OltInfo;
use App\Services\EcomService;
use App\Services\SnmpManager;
use App\Services\VsolManager;
use App\Services\CdataService;
use App\Services\VsolManager2;
use Illuminate\Console\Command;
use Symfony\Component\Yaml\Yaml;
use App\Models\OltOnuInformation;
use App\Services\TbsService;
use Illuminate\Support\Facades\DB;

class ProcessSnmpManagers extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'snmp:process';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Process SNMP managers and update ONU information in the database.';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $oltInfoRecords = OltInfo::all();

        if (!$oltInfoRecords) {
            $this->error("Configuration Data not found: $oltInfoRecords");
            return Command::FAILURE;
        }

        if (checkAPI()) {
            $activeClients = mikrotikOnlineAndOfflineUsers();
            $usersByMac = collect($activeClients['allOnlineUsersWithoutMap'])->keyBy("caller-id");
        } else {
            $activeClients = DB::table('radacct')
                ->select('username', 'callingstationid')
                ->where('acctstoptime', null)
                ->get();
            $usersByMac = $activeClients->keyBy('callingstationid');
        }


        $config = $oltInfoRecords;

        foreach ($config as $manager) {
            try {
                $this->info("Processing SNMP Manager: {$manager->olt_address}");

                $oids = [
                    'oltName' => $manager->olt_name,
                    'vlanMac' => $manager->vlan_mac,
                    'onuId' => $manager->onu_id,
                    'onuInterfaceName' => $manager->onu_interface_name,
                    'onuLaser' => $manager->onu_laser,
                ];

                if ($manager->olt_company == 'Vsol') {
                    if ($manager->olt_type == 'Epon') {
                        $snmpManager = new VsolManager(
                            $manager->olt_address,
                            $manager->community,
                            $oids,
                            $manager->port
                        );
                    } else {
                        $snmpManager = new VsolManager2(
                            $manager->olt_address,
                            $manager->community,
                            $oids,
                            $manager->port
                        );
                    }
                } elseif ($manager->olt_company == 'Cdata') {
                    $snmpManager = new CdataService(
                        $manager->olt_address,
                        $manager->community,
                        $oids,
                        $manager->port
                    );
                } elseif ($manager->olt_company == 'Ecom') {
                    $snmpManager = new EcomService(
                        $manager->olt_address,
                        $manager->community,
                        $oids,
                        $manager->port
                    );
                } elseif ($manager->olt_company == 'TBS') {
                    $snmpManager = new TbsService(
                        $manager->olt_address,
                        $manager->community,
                        $oids,
                        $manager->port
                    );
                } else {
                    $snmpManager = new SnmpManager(
                        $manager->olt_address,
                        $manager->community,
                        $oids,
                        $manager->port
                    );
                }

                $oltName = $snmpManager->getOltName();
                $onuData = $snmpManager->getAllOnuInformation();

                foreach ($onuData as $onu) {
                    $this->updateDatabase($manager->olt_address, $oltName, $onu, $usersByMac, $manager);
                }

                $this->info("Successfully processed SNMP Manager: {$manager->olt_address}");
            } catch (\Exception $e) {
                $this->error("Error processing SNMP Manager: {$manager->olt_address}, Error: {$e->getMessage()}");
            }
        }

        return Command::SUCCESS;
    }

    private function updateDatabase($oltAddress, $oltName, $onu, $usersByMac, $manager)
    {
        try {
            if ($manager->olt_company == 'BDCom') {
                $onu['macAddress'] = strtoupper(implode(':', str_split($onu['macAddress'], 2)));
            }
            $onuInfo = OltOnuInformation::firstOrNew(
                [
                    'mac' => $onu['macAddress'],
                ]
            );

            if (checkAPI()) {
                $userExist = $usersByMac[strtoupper(implode(':', str_split($onu['macAddress'], 2)))] ?? null;
            } else {
                $userExist = $usersByMac[$onu['macAddress']] ?? null;
            }

            if (!$userExist) {
                $userExist = $usersByMac[strtoupper($onu['macAddress'])] ?? null;
            }

            if ($userExist) {
                if (checkAPI()) {
                    $onuInfo->username = $userExist["name"];
                } else {
                    $onuInfo->username = $userExist->username;
                }
            }

            $onuInfo->fill([
                'oltaddress' => $oltAddress,
                'onuid' => $onu['onuId'],
                'Vlan' => $onu['vLan'] ?? null,
                'interface' => $onu['interfaceName'] ?? null,
                'laser' => $onu['onuLaser'],
                'oltName' => $oltName ?? $oltAddress,
                'username' => ($userExist && checkAPI() ? (isset($userExist["name"]) ? $userExist["name"] : null) : ($userExist && !checkAPI() ? (isset($userExist->username) ? $userExist->username : null) : null))
            ]);

            $onuInfo->save();
        } catch (\Exception $e) {
            $this->error("Error updating database for ONU ID: {$onu['onuId']}, Error: {$e->getMessage()}");
        }
    }
}
