<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\DnsZoneAssignment;
use App\Models\User;
use App\Services\PowerDNSService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class PowerDNSController extends Controller
{
    protected $powerDNS;

    public function __construct(PowerDNSService $powerDNS)
    {
        $this->powerDNS = $powerDNS;
    }

    /**
     * Dashboard PowerDNS - statistici generale
     */
    public function index()
    {
        try {
            // Obține toate nameserverele configurate
            $nameServers = \App\Models\NameServer::all();
            
            if ($nameServers->isEmpty()) {
                return view('admin.powerdns.index', [
                    'error' => 'Nu există nameservere configurate în sistem.',
                    'stats' => ['data' => ['total' => 0, 'forward' => 0, 'arpa_v4' => 0, 'arpa_v6' => 0]],
                    'servers' => null,
                    'nameServers' => collect()
                ]);
            }
            
            // Verifică dacă există nameservere configurate corect
            $configuredNameServers = $nameServers->filter(function($ns) {
                return !empty($ns->api_url) && !empty($ns->api_port);
            });
            
            if ($configuredNameServers->isEmpty()) {
                return view('admin.powerdns.index', [
                    'error' => 'Nameserverele nu au API URL și API Port configurate. Vă rugăm să configurați nameserverele.',
                    'stats' => ['data' => ['total' => 0, 'forward' => 0, 'arpa_v4' => 0, 'arpa_v6' => 0]],
                    'servers' => null,
                    'nameServers' => $nameServers
                ]);
            }
            
            // Agregă statistici de la toate nameserverele
            $aggregatedStats = [
                'total' => 0,
                'forward' => 0,
                'arpa_v4' => 0,
                'arpa_v6' => 0,
            ];
            
            $allZones = [];
            $hasErrors = false;
            $errorMessages = [];
            
            foreach ($configuredNameServers as $nameServer) {
                try {
                    $zones = $this->powerDNS->getZones($nameServer);
                    
                    if ($zones['success'] && isset($zones['data'])) {
                        foreach ($zones['data'] as $zone) {
                            $zoneName = $zone['name'] ?? '';
                            
                            // Evită duplicatele
                            if (!in_array($zoneName, $allZones)) {
                                $allZones[] = $zoneName;
                                $aggregatedStats['total']++;
                                
                                if (str_ends_with($zoneName, '.in-addr.arpa.')) {
                                    $aggregatedStats['arpa_v4']++;
                                } elseif (str_ends_with($zoneName, '.ip6.arpa.')) {
                                    $aggregatedStats['arpa_v6']++;
                                } else {
                                    $aggregatedStats['forward']++;
                                }
                            }
                        }
                    } else {
                        $hasErrors = true;
                        $errorMessages[] = "{$nameServer->name}: " . ($zones['error'] ?? 'Unknown error');
                    }
                } catch (\Exception $e) {
                    $hasErrors = true;
                    $errorMessages[] = "{$nameServer->name}: " . $e->getMessage();
                    \Log::error("PowerDNS error for {$nameServer->name}: " . $e->getMessage());
                }
            }
            
            $error = null;
            if ($hasErrors) {
                $error = 'Erori la conectarea cu unele nameservere: ' . implode('; ', $errorMessages);
            }
            
            return view('admin.powerdns.index', [
                'stats' => ['success' => true, 'data' => $aggregatedStats],
                'servers' => ['success' => true],
                'nameServers' => $nameServers,
                'error' => $error
            ]);
        } catch (\Exception $e) {
            \Log::error('PowerDNS Dashboard Error: ' . $e->getMessage());
            
            return view('admin.powerdns.index', [
                'error' => 'Eroare la conectarea cu PowerDNS: ' . $e->getMessage(),
                'stats' => ['data' => ['total' => 0, 'forward' => 0, 'arpa_v4' => 0, 'arpa_v6' => 0]],
                'servers' => null,
                'nameServers' => \App\Models\NameServer::all()
            ]);
        }
    }

    /**
     * Listare servere PowerDNS
     */
    public function servers()
    {
        $result = $this->powerDNS->getServers();

        if (!$result['success']) {
            return redirect()->route('admin.powerdns.index')
                ->with('error', $result['error'] ?? 'Eroare la conectarea cu PowerDNS');
        }

        return view('admin.powerdns.servers', [
            'servers' => $result['data']
        ]);
    }

    /**
     * Listare zone DNS
     */
    public function zones(Request $request)
    {
        $type = $request->get('type', 'all'); // all, forward, arpa_v4, arpa_v6
        $search = $request->get('search');

        // Obține toate nameserverele configurate
        $nameServers = \App\Models\NameServer::all();
        $configuredNameServers = $nameServers->filter(function($ns) {
            return !empty($ns->api_url) && !empty($ns->api_port);
        });

        if ($configuredNameServers->isEmpty()) {
            return redirect()->route('admin.powerdns.index')
                ->with('error', 'Nameserverele nu au API URL și API Port configurate.');
        }

        // Agregă zone de la toate nameserverele
        $allZones = [];
        $hasErrors = false;
        
        foreach ($configuredNameServers as $nameServer) {
            try {
                $result = $this->powerDNS->getZones($nameServer);
                
                if ($result['success'] && isset($result['data'])) {
                    foreach ($result['data'] as $zone) {
                        $zoneName = $zone['name'] ?? '';
                        // Evită duplicatele
                        if (!isset($allZones[$zoneName])) {
                            $allZones[$zoneName] = $zone;
                        }
                    }
                } else {
                    $hasErrors = true;
                    \Log::warning("Failed to get zones from {$nameServer->name}: " . ($result['error'] ?? 'Unknown error'));
                }
            } catch (\Exception $e) {
                $hasErrors = true;
                \Log::error("Exception getting zones from {$nameServer->name}: " . $e->getMessage());
            }
        }

        $zones = collect(array_values($allZones));

        // Adaugă informații despre atribuiri și înregistrări pentru fiecare zonă
        $zones = $zones->map(function($zone) use ($configuredNameServers) {
            $zoneId = $zone['id'] ?? $zone['name'];

            // Verifică dacă este o zonă locală (creată de un utilizator)
            $localZone = \App\Models\DnsZone::where('domain', rtrim($zoneId, '.'))->with(['user', 'nameServers'])->first();
            $zone['local_zone'] = $localZone;
            $zone['owner'] = $localZone ? $localZone->user : null;

            // Obține înregistrările de pe nameserverele atribuite zonei
            if ($localZone && $localZone->nameServers->isNotEmpty()) {
                // Zonă locală cu nameservere atribuite
                $firstNS = $localZone->nameServers->first();
                
                // Cache key pentru această zonă pe acest nameserver
                $cacheKey = "powerdns_zone_details_{$zoneId}_{$firstNS->id}";
                
                $zoneDetails = cache()->remember($cacheKey, 300, function() use ($zoneId, $firstNS) {
                    return $this->powerDNS->getZone($zoneId, $firstNS);
                });
                
                if ($zoneDetails['success']) {
                    $zone['rrsets'] = $zoneDetails['data']['rrsets'] ?? [];
                    $zone['records_count'] = count($zone['rrsets']);
                    $zone['serial'] = $zoneDetails['data']['serial'] ?? 'N/A';
                    $zone['kind'] = $zoneDetails['data']['kind'] ?? 'N/A';
                } else {
                    $zone['rrsets'] = [];
                    $zone['records_count'] = 0;
                    $zone['serial'] = 'Error';
                    $zone['kind'] = 'N/A';
                }
            } else {
                // Zonă fără atribuire locală - încearcă primul nameserver disponibil
                $firstNS = $configuredNameServers->first();
                if ($firstNS) {
                    $cacheKey = "powerdns_zone_details_{$zoneId}_default";
                    
                    $zoneDetails = cache()->remember($cacheKey, 300, function() use ($zoneId, $firstNS) {
                        return $this->powerDNS->getZone($zoneId, $firstNS);
                    });
                    
                    if ($zoneDetails['success']) {
                        $zone['rrsets'] = $zoneDetails['data']['rrsets'] ?? [];
                        $zone['records_count'] = count($zone['rrsets']);
                        $zone['serial'] = $zoneDetails['data']['serial'] ?? 'N/A';
                        $zone['kind'] = $zoneDetails['data']['kind'] ?? 'N/A';
                    } else {
                        $zone['rrsets'] = [];
                        $zone['records_count'] = 0;
                        $zone['serial'] = 'Error';
                        $zone['kind'] = 'N/A';
                    }
                } else {
                    $zone['rrsets'] = [];
                    $zone['records_count'] = 0;
                    $zone['serial'] = 'N/A';
                    $zone['kind'] = 'N/A';
                }
            }

            // Adaugă informații despre atribuiri
            $assignments = \App\Models\DnsZoneAssignment::where('zone_name', $zoneId)->with('user')->get();
            $zone['assignments'] = $assignments;
            $zone['assigned_users_count'] = $assignments->count();

            return $zone;
        });

        // Filtrare după tip
        if ($type !== 'all') {
            $zones = $zones->filter(function($zone) use ($type) {
                $name = $zone['name'] ?? '';

                if ($type === 'forward') {
                    return !str_ends_with($name, '.in-addr.arpa.') && !str_ends_with($name, '.ip6.arpa.');
                } elseif ($type === 'arpa_v4') {
                    return str_ends_with($name, '.in-addr.arpa.');
                } elseif ($type === 'arpa_v6') {
                    return str_ends_with($name, '.ip6.arpa.');
                }

                return true;
            });
        }

        // Filtrare după căutare
        if ($search) {
            $zones = $zones->filter(function($zone) use ($search) {
                return str_contains(strtolower($zone['name'] ?? ''), strtolower($search));
            });
        }

        // Statistici pentru taburi (folosim zona agregată)
        $allZonesCollection = collect(array_values($allZones));
        $stats = [
            'all' => $allZonesCollection->count(),
            'forward' => $allZonesCollection->filter(fn($z) => !str_ends_with($z['name'] ?? '', '.in-addr.arpa.') && !str_ends_with($z['name'] ?? '', '.ip6.arpa.'))->count(),
            'arpa_v4' => $allZonesCollection->filter(fn($z) => str_ends_with($z['name'] ?? '', '.in-addr.arpa.'))->count(),
            'arpa_v6' => $allZonesCollection->filter(fn($z) => str_ends_with($z['name'] ?? '', '.ip6.arpa.'))->count(),
        ];

        return view('admin.powerdns.zones', compact('zones', 'type', 'search', 'stats'));
    }

    /**
     * Detalii zonă DNS + înregistrări
     */
    public function zoneShow($zoneId)
    {
        // Găsește zona locală și nameserverele atribuite
        $localZone = \App\Models\DnsZone::where('domain', rtrim($zoneId, '.'))->with(['user', 'nameServers'])->first();
        
        $nameServer = null;
        if ($localZone && $localZone->nameServers->isNotEmpty()) {
            // Folosește primul nameserver atribuit
            $nameServer = $localZone->nameServers->first();
        } else {
            // Folosește primul nameserver disponibil
            $nameServer = \App\Models\NameServer::whereNotNull('api_url')
                ->whereNotNull('api_port')
                ->first();
        }
        
        if (!$nameServer) {
            return redirect()->route('admin.powerdns.zones')
                ->with('error', 'Nu există nameservere configurate pentru această zonă.');
        }
        
        $zoneResult = $this->powerDNS->getZone($zoneId, $nameServer);

        if (!$zoneResult['success']) {
            return redirect()->route('admin.powerdns.zones')
                ->with('error', $zoneResult['error'] ?? 'Zona nu a fost găsită');
        }

        $zone = $zoneResult['data'];
        $records = $zone['rrsets'] ?? [];

        return view('admin.powerdns.show', compact('zone', 'records', 'zoneId', 'localZone', 'nameServer'));
    }

    /**
     * Ștergere zonă DNS de pe toate nameserverele
     */
    public function deleteZone($zoneId)
    {
        // Obține toate nameserverele configurate
        $nameServers = \App\Models\NameServer::whereNotNull('api_url')
            ->whereNotNull('api_port')
            ->get();
        
        if ($nameServers->isEmpty()) {
            return redirect()->back()
                ->with('error', 'Nu există nameservere configurate.');
        }
        
        $deletedFrom = [];
        $failedFrom = [];
        
        // Încearcă să ștergi zona de pe fiecare nameserver
        foreach ($nameServers as $nameServer) {
            try {
                $result = $this->powerDNS->deleteZone($zoneId, $nameServer);
                
                if ($result['success']) {
                    $deletedFrom[] = $nameServer->name;
                } else {
                    // Zona nu există pe acest nameserver (probabil)
                    \Log::info("Zone {$zoneId} not found on {$nameServer->name}: " . ($result['error'] ?? 'Unknown'));
                }
            } catch (\Exception $e) {
                $failedFrom[] = $nameServer->name;
                \Log::error("Failed to delete zone {$zoneId} from {$nameServer->name}: " . $e->getMessage());
            }
        }
        
        // Șterge și din baza de date locală
        $localZone = \App\Models\DnsZone::where('domain', rtrim($zoneId, '.'))->first();
        if ($localZone) {
            // Șterge relațiile din pivot
            $localZone->nameServers()->detach();
            // Șterge zona
            $localZone->delete();
        }
        
        // Construiește mesajul
        if (!empty($deletedFrom)) {
            $serverList = implode(', ', $deletedFrom);
            $message = "Zona {$zoneId} a fost ștearsă cu succes de pe: {$serverList}";
            
            if (!empty($failedFrom)) {
                $failedList = implode(', ', $failedFrom);
                $message .= ". Erori pe: {$failedList}";
            }
            
            return redirect()->route('admin.powerdns.zones')
                ->with('success', $message);
        } else {
            return redirect()->back()
                ->with('error', "Zona {$zoneId} nu a fost găsită pe niciun nameserver.");
        }
    }

    /**
     * Ștergere înregistrare DNS
     */
    public function deleteRecord(Request $request, $zoneId)
    {
        $request->validate([
            'name' => 'required|string',
            'type' => 'required|string',
        ]);

        $result = $this->powerDNS->deleteRecord(
            $zoneId,
            $request->input('name'),
            $request->input('type')
        );

        if (!$result['success']) {
            return redirect()->back()
                ->with('error', $result['error'] ?? 'Eroare la ștergerea înregistrării');
        }

        return redirect()->route('admin.powerdns.zones.show', $zoneId)
            ->with('success', 'Înregistrarea a fost ștearsă cu succes');
    }

    /**
     * Afișare formular atribuire zonă
     */
    public function assignZone($zoneId)
    {
        // Verifică dacă zona există în PowerDNS
        $zoneResult = $this->powerDNS->getZone($zoneId);

        if (!$zoneResult['success']) {
            return redirect()->route('admin.powerdns.zones')
                ->with('error', 'Zona nu a fost găsită în PowerDNS');
        }

        $zone = $zoneResult['data'];

        // Obține toți utilizatorii (exceptând admin)
        $users = User::where('role', '!=', 'admin')->get();

        // Obține atribuirile existente pentru această zonă
        $assignments = DnsZoneAssignment::getZoneUsers($zoneId);

        return view('admin.powerdns.assign', compact('zone', 'users', 'assignments', 'zoneId'));
    }

    /**
     * Salvare atribuire zonă
     */
    public function storeAssignment(Request $request, $zoneId)
    {
        $request->validate([
            'user_id' => 'required|exists:users,id',
            'access_level' => 'required|in:full,records_only',
        ]);

        // Verifică dacă zona există
        $zoneResult = $this->powerDNS->getZone($zoneId);

        if (!$zoneResult['success']) {
            return redirect()->back()
                ->with('error', 'Zona nu a fost găsită în PowerDNS');
        }

        // Verifică dacă atribuirea nu există deja
        if (DnsZoneAssignment::isZoneAssigned($zoneId, $request->user_id)) {
            return redirect()->back()
                ->with('error', 'Zona este deja atribuită acestui utilizator');
        }

        // Creează atribuirea
        DnsZoneAssignment::create([
            'zone_name' => $zoneId,
            'user_id' => $request->user_id,
            'access_level' => $request->access_level,
            'assigned_by' => Auth::id(),
        ]);

        return redirect()->route('admin.powerdns.zones.assign', $zoneId)
            ->with('success', 'Zona a fost atribuită cu succes utilizatorului');
    }

    /**
     * Ștergere atribuire zonă
     */
    public function removeAssignment($zoneId, $assignmentId)
    {
        $assignment = DnsZoneAssignment::findOrFail($assignmentId);

        if ($assignment->zone_name !== $zoneId) {
            return redirect()->back()
                ->with('error', 'Atribuirea nu corespunde cu zona selectată');
        }

        $assignment->delete();

        return redirect()->back()
            ->with('success', 'Atribuirea a fost eliminată cu succes');
    }
}
