<?php

namespace App\Http\Controllers;

use App\Models\OltDevice;
use App\Models\OltOnu;
use App\Models\OltPort;
use App\Services\OltSshService;
use Illuminate\Http\Request;

class OnuController extends Controller
{
    public function index(Request $request)
    {
        $query = OltOnu::with('port.device');

        if ($request->device_id) {
            $portIds = OltPort::where('olt_device_id', $request->device_id)->pluck('id');
            $query->whereIn('olt_port_id', $portIds);
        }
        if ($request->status) {
            $query->where('status', $request->status);
        }
        if ($request->search) {
            $query->where(function ($q) use ($request) {
                $q->where('serial_number', 'like', '%' . $request->search . '%')
                  ->orWhere('customer_name', 'like', '%' . $request->search . '%');
            });
        }

        $onus    = $query->latest()->paginate(25)->withQueryString();
        $devices = OltDevice::where('active', true)->get();
        return view('onus.index', compact('onus', 'devices'));
    }

    public function create(Request $request)
    {
        $devices = OltDevice::where('active', true)->get();
        $selectedDevice = $request->device_id ? OltDevice::with('ports')->find($request->device_id) : null;

        // Predefined speed profiles
        $speedProfiles = ['UP512K', 'UP1000M', 'UP1G', 'UP2000M', 'UP4000M', 'UP10000M'];
        $onuTypes      = ['ZTE-F680', 'ZTE-F660P', 'ZTE-F601', 'ZTE-F660', 'ZTE-F670L', 'ZTE-F6600P'];

        // Pre-fill from rogue ONU if passed
        $prefill = [
            'sn'    => $request->sn,
            'frame' => $request->frame,
            'slot'  => $request->slot,
            'port'  => $request->port,
        ];

        return view('onus.create', compact('devices', 'selectedDevice', 'speedProfiles', 'onuTypes', 'prefill'));
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'olt_device_id'        => 'required|exists:olt_devices,id',
            'frame'                => 'required|integer|min:1',
            'slot'                 => 'required|integer|min:1',
            'port'                 => 'required|integer|min:1',
            'serial_number'        => 'required|string|max:50',
            'onu_type'             => 'required|string|max:50',
            'customer_name'        => 'nullable|string|max:100',
            'customer_description' => 'nullable|string|max:255',
            'vlan'                 => 'required|integer|min:1|max:4094',
            'tcont_profile'        => 'required|string|max:50',
            'service_name'         => 'required|string|max:50',
            'onu_number'           => 'nullable|integer|min:1',
            'preview_only'         => 'nullable|boolean',
        ]);

        // Find or create the port
        $oltPort = OltPort::firstOrCreate([
            'olt_device_id' => $validated['olt_device_id'],
            'frame'         => $validated['frame'],
            'slot'          => $validated['slot'],
            'port'          => $validated['port'],
        ]);

        $onuNumber = $validated['onu_number'] ?? $oltPort->next_onu_number;

        $onu = new OltOnu([
            'olt_port_id'          => $oltPort->id,
            'onu_number'           => $onuNumber,
            'serial_number'        => strtoupper($validated['serial_number']),
            'onu_type'             => $validated['onu_type'],
            'customer_name'        => $validated['customer_name'],
            'customer_description' => $validated['customer_description'],
            'vlan'                 => $validated['vlan'],
            'tcont_profile'        => $validated['tcont_profile'],
            'service_port'         => $validated['port'], // always equals the PON port number
            'service_name'         => $validated['service_name'],
            'status'               => 'pending',
        ]);

        $commands = $onu->buildCliCommands();

        // If only preview, return commands without saving
        if ($request->boolean('preview_only')) {
            return response()->json(['commands' => $commands]);
        }

        // Send via SSH
        $device = OltDevice::find($validated['olt_device_id']);
        $ssh    = new OltSshService($device);

        try {
            if (!$ssh->connect()) {
                return back()->withInput()->with('error', 'No se pudo conectar a la OLT via SSH.');
            }

            $output = $ssh->sendCommands($commands);

            // Persist configuration to NVRAM
            $ssh->runCommand('write');

            $ssh->disconnect();

            // Check if OLT rejected any command
            $hasError = preg_match('/%\s*Error|Invalid input|Unrecognized command|failed/i', $output);

            if ($hasError) {
                $onu->status     = 'pending';
                $onu->raw_config = $commands;
                $onu->save();

                $ssh->logActivity('authorize_onu', $onu->serial_number, $commands, $output, false);

                return redirect()->route('onus.show', $onu)
                    ->with('error', 'La OLT rechazó algunos comandos. Revisa la configuración.')
                    ->with('ssh_output', $output);
            }

            $onu->status        = 'authorized';
            $onu->authorized_at = now();
            $onu->authorized_by = auth()->id();
            $onu->raw_config    = $commands;
            $onu->save();

            $ssh->logActivity('authorize_onu', $onu->interface_name, $commands, $output, true);

            return redirect()->route('onus.show', $onu)
                ->with('success', "ONU {$onu->serial_number} autorizada correctamente.");
        } catch (\Exception $e) {
            $ssh->logActivity('authorize_onu', $onu->serial_number, $commands, $e->getMessage(), false);
            return back()->withInput()->with('error', 'Error SSH: ' . $e->getMessage());
        }
    }

    public function show(OltOnu $onu)
    {
        $onu->load('port.device', 'authorizedBy');
        return view('onus.show', compact('onu'));
    }

    public function edit(OltOnu $onu)
    {
        $onu->load('port.device');
        $speedProfiles = ['UP512K', 'UP1000M', 'UP1G', 'UP2000M', 'UP4000M', 'UP10000M'];
        $onuTypes      = ['ZTE-F680', 'ZTE-F660P', 'ZTE-F601', 'ZTE-F660', 'ZTE-F670L', 'ZTE-F6600P'];
        return view('onus.edit', compact('onu', 'speedProfiles', 'onuTypes'));
    }

    public function update(Request $request, OltOnu $onu)
    {
        $validated = $request->validate([
            'customer_name'        => 'nullable|string|max:100',
            'customer_description' => 'nullable|string|max:255',
            'vlan'                 => 'required|integer|min:1|max:4094',
            'tcont_profile'        => 'required|string|max:50',
            'service_name'         => 'required|string|max:50',
        ]);

        // service_port is always the PON port number — not editable
        $validated['service_port'] = $onu->port->port;

        $onu->update($validated);
        return redirect()->route('onus.show', $onu)->with('success', 'ONU actualizada.');
    }

    public function destroy(OltOnu $onu)
    {
        $onu->update(['status' => 'disabled']);
        return redirect()->route('onus.index')->with('success', 'ONU deshabilitada.');
    }

    public function nextPosition(Request $request)
    {
        $request->validate([
            'olt_device_id' => 'required|exists:olt_devices,id',
            'frame'         => 'required|integer|min:1',
            'slot'          => 'required|integer|min:1',
            'port'          => 'required|integer|min:1',
        ]);

        $device = OltDevice::findOrFail($request->olt_device_id);

        try {
            $ssh = new OltSshService($device);
            if (!$ssh->connect()) {
                return response()->json(['success' => false, 'message' => 'No se pudo conectar a la OLT.']);
            }

            $used = $ssh->getUsedOnuPositions($request->frame, $request->slot, $request->port);
            $next = $ssh->getNextOnuPosition($request->frame, $request->slot, $request->port);
            $ssh->disconnect();

            return response()->json([
                'success'       => true,
                'next_position' => $next,
                'used_count'    => count($used),
                'used'          => $used,
            ]);
        } catch (\Throwable $e) {
            return response()->json(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
    }

    public function opticalPower(OltOnu $onu)
    {
        $onu->load('port.device');
        $device = $onu->port->device;
        $p = $onu->port;

        try {
            $ssh = new OltSshService($device);
            if (!$ssh->connect()) {
                return response()->json(['success' => false, 'message' => 'No se pudo conectar a la OLT.']);
            }

            $power = $ssh->getOnuOpticalPower($p->frame, $p->slot, $p->port, $onu->onu_number);
            $ssh->disconnect();

            return response()->json(['success' => true, 'power' => $power]);
        } catch (\Throwable $e) {
            return response()->json(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
    }

    public function previewCommands(Request $request)
    {
        $request->validate([
            'olt_device_id'        => 'required|exists:olt_devices,id',
            'frame'                => 'required|integer',
            'slot'                 => 'required|integer',
            'port'                 => 'required|integer',
            'serial_number'        => 'required|string',
            'onu_type'             => 'required|string',
            'customer_name'        => 'nullable|string',
            'customer_description' => 'nullable|string',
            'vlan'                 => 'required|integer',
            'tcont_profile'        => 'required|string',
            'service_name'         => 'required|string',
            'onu_number'           => 'nullable|integer',
        ]);

        $oltPort = OltPort::firstOrNew([
            'olt_device_id' => $request->olt_device_id,
            'frame'         => $request->frame,
            'slot'          => $request->slot,
            'port'          => $request->port,
        ]);

        if (!$oltPort->exists) {
            $oltPort->frame = $request->frame;
            $oltPort->slot  = $request->slot;
            $oltPort->port  = $request->port;
        }

        $onuNumber = $request->onu_number ?? ($oltPort->next_onu_number ?? 1);

        $onu = new OltOnu([
            'onu_number'           => $onuNumber,
            'serial_number'        => strtoupper($request->serial_number),
            'onu_type'             => $request->onu_type,
            'customer_name'        => $request->customer_name,
            'customer_description' => $request->customer_description,
            'vlan'                 => $request->vlan,
            'tcont_profile'        => $request->tcont_profile,
            'service_port'         => $request->port, // always equals the PON port number
            'service_name'         => $request->service_name,
        ]);
        $onu->setRelation('port', $oltPort);

        return response()->json(['commands' => $onu->buildCliCommands()]);
    }
}
