<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\NameServer;
use App\Models\ActivityLog;
use App\Services\NameServerService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class NameServerController extends Controller
{
    protected $nameServerService;

    public function __construct(NameServerService $nameServerService)
    {
        $this->nameServerService = $nameServerService;
    }

    public function index(Request $request)
    {
        $query = NameServer::withCount('dnsZones');

        // Filtre
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }
        if ($request->filled('region')) {
            $query->where('region', $request->region);
        }
        if ($request->filled('provider')) {
            $query->where('provider', $request->provider);
        }
        if ($request->filled('is_active')) {
            $query->where('is_active', $request->boolean('is_active'));
        }

        $nameServers = $query->orderBy('priority')->paginate(15);

        // Statistici
        $stats = [
            'total' => NameServer::count(),
            'online' => NameServer::where('status', 'online')->count(),
            'offline' => NameServer::where('status', 'offline')->count(),
            'avg_response' => NameServer::where('status', 'online')->avg('response_time_ms') ?? 0,
            'total_zones' => NameServer::sum('current_zones'),
        ];

        return view('admin.nameservers.index', compact('nameServers', 'stats'));
    }

    public function create()
    {
        return view('admin.nameservers.create');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'hostname' => 'required|string|unique:name_servers,hostname',
            'ip_address' => 'required|ip',
            'ipv6_address' => 'nullable|ipv6',
            'api_url' => 'nullable|url',
            'api_key' => 'nullable|string',
            'api_type' => 'required|in:powerdns,bind,custom',
            'api_port' => 'required|integer|min:1|max:65535',
            'server_id' => 'required|string',
            'country_code' => 'nullable|string|size:2',
            'city' => 'nullable|string',
            'region' => 'nullable|in:EU,NA,AS,OC,AF,SA',
            'latitude' => 'nullable|numeric',
            'longitude' => 'nullable|numeric',
            'provider' => 'nullable|string',
            'datacenter' => 'nullable|string',
            'is_active' => 'required|boolean',
            'is_primary' => 'required|boolean',
            'priority' => 'required|integer|min:1|max:100',
            'weight' => 'required|integer|min:1',
            'max_zones' => 'nullable|integer|min:1',
            'description' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        // Conversie explicită pentru boolean-uri (pentru siguranță)
        $validated['is_active'] = (bool) $validated['is_active'];
        $validated['is_primary'] = (bool) $validated['is_primary'];

        $nameServer = NameServer::create($validated);

        // Health check automat după creare
        try {
            $this->nameServerService->checkHealth($nameServer);
        } catch (\Exception $e) {
            Log::warning("Health check failed for new NameServer {$nameServer->id}: " . $e->getMessage());
        }

        ActivityLog::log('create', "A creat serverul NS: {$nameServer->name}", 'NameServer', $nameServer->id);

        return redirect()->route('admin.nameservers.index')
            ->with('success', 'Serverul NS a fost creat cu succes.');
    }

    public function show(Request $request, NameServer $nameServer)
    {
        // Parametri pentru căutare și paginare zone
        $zoneSearch = $request->get('zone_search', '');
        $zonesPerPage = 5;

        // Încarcă zonele care au acest NS ca server primar (din baza de date locală)
        $localZonesQuery = \App\Models\DnsZone::with('user')
            ->where(function($query) use ($nameServer) {
                $query->where('name_server_id', $nameServer->id)
                    ->orWhereJsonContains('allocated_nameservers', $nameServer->id);
            });

        // Aplică căutarea
        if ($zoneSearch) {
            $localZonesQuery->where('domain', 'like', "%{$zoneSearch}%");
        }

        // Numără zonele totale
        $totalLocalZones = $localZonesQuery->count();

        // Paginare
        $localZones = $localZonesQuery->orderBy('domain')->paginate($zonesPerPage, ['*'], 'zones_page');

        // Obține zonele din PowerDNS (fără paginare, dar cu search)
        $powerDNSZones = collect();
        $powerDNSResult = $this->nameServerService->getZones($nameServer);
        if ($powerDNSResult['success'] && isset($powerDNSResult['data'])) {
            $powerDNSZones = collect($powerDNSResult['data'])->map(function($zone) {
                // Creează un obiect similar cu DnsZone pentru afișare
                return (object)[
                    'id' => 'pdns_' . $zone['id'],
                    'domain' => rtrim($zone['name'], '.'),
                    'type' => $zone['kind'] ?? 'NATIVE',
                    'is_powerdns_only' => true,
                    'powerdns_data' => $zone,
                ];
            });

            // Aplică search pentru PowerDNS zones
            if ($zoneSearch) {
                $powerDNSZones = $powerDNSZones->filter(function($zone) use ($zoneSearch) {
                    return stripos($zone->domain, $zoneSearch) !== false;
                });
            }
        }

        // Statistici DNSSEC
        $dnssecStats = [
            'total_zones' => $totalLocalZones,
            'dnssec_enabled' => \App\Models\DnsZone::where(function($query) use ($nameServer) {
                    $query->where('name_server_id', $nameServer->id)
                        ->orWhereJsonContains('allocated_nameservers', $nameServer->id);
                })->where('dnssec_enabled', true)->count(),
            'dnssec_disabled' => 0,
        ];
        $dnssecStats['dnssec_disabled'] = $dnssecStats['total_zones'] - $dnssecStats['dnssec_enabled'];
        $dnssecStats['dnssec_percentage'] = $dnssecStats['total_zones'] > 0
            ? round(($dnssecStats['dnssec_enabled'] / $dnssecStats['total_zones']) * 100, 1)
            : 0;

        // Istoric incidente (ultimele 30 zile)
        $incidentHistory = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(30))
            ->whereIn('status', ['offline', 'degraded'])
            ->orderBy('checked_at', 'desc')
            ->limit(50)
            ->get()
            ->map(function($stat) {
                return [
                    'date' => $stat->checked_at->format('d.m.Y H:i'),
                    'status' => $stat->status,
                    'response_time' => $stat->response_time_ms,
                    'error' => $stat->error_message,
                ];
            });

        $stats = $this->nameServerService->getStatistics($nameServer);

        // Date pentru grafice - ultimele 24h (la fiecare 5 minute = 288 puncte)
        $chartData24h = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDay())
            ->orderBy('checked_at')
            ->get()
            ->map(function($stat) {
                return [
                    'time' => $stat->checked_at->format('H:i'),
                    'response_time' => $stat->response_time_ms,
                    'status' => $stat->status,
                    'zones' => $stat->zones_count,
                ];
            });

        // Date pentru grafice - ultimele 7 zile (medie pe zi)
        $chartData7days = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(7))
            ->selectRaw('DATE(checked_at) as date, AVG(response_time_ms) as avg_response, AVG(zones_count) as avg_zones, COUNT(*) as checks')
            ->groupBy('date')
            ->orderBy('date')
            ->get()
            ->map(function($stat) {
                return [
                    'date' => \Carbon\Carbon::parse($stat->date)->format('d M'),
                    'avg_response' => round($stat->avg_response),
                    'avg_zones' => round($stat->avg_zones),
                    'checks' => $stat->checks,
                ];
            });

        // Date pentru grafice - ultimele 30 zile
        $chartData30days = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(30))
            ->selectRaw('DATE(checked_at) as date, AVG(response_time_ms) as avg_response, AVG(zones_count) as avg_zones')
            ->groupBy('date')
            ->orderBy('date')
            ->get()
            ->map(function($stat) {
                return [
                    'date' => \Carbon\Carbon::parse($stat->date)->format('d M'),
                    'avg_response' => round($stat->avg_response),
                    'avg_zones' => round($stat->avg_zones),
                ];
            });

        // Date pentru grafice - ultimul an (365 zile, grupate pe lună)
        $chartData1year = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subYear())
            ->selectRaw('DATE_FORMAT(checked_at, "%Y-%m") as month, AVG(response_time_ms) as avg_response, AVG(zones_count) as avg_zones')
            ->groupBy('month')
            ->orderBy('month')
            ->get()
            ->map(function($stat) {
                return [
                    'date' => \Carbon\Carbon::parse($stat->month . '-01')->format('M Y'),
                    'avg_response' => round($stat->avg_response),
                    'avg_zones' => round($stat->avg_zones),
                ];
            });

        // Uptime calculation (ultimele 24h)
        $totalChecks24h = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDay())
            ->count();

        $onlineChecks24h = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDay())
            ->where('status', 'online')
            ->count();

        $uptime24h = $totalChecks24h > 0 ? round(($onlineChecks24h / $totalChecks24h) * 100, 2) : 0;

        // Statistici extinse pentru fiecare perioadă
        $extendedStats = [];

        // 24h stats
        $stats24h = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDay())
            ->selectRaw('AVG(response_time_ms) as avg_response, MIN(response_time_ms) as min_response, MAX(response_time_ms) as max_response, COUNT(*) as total_checks')
            ->first();

        $extendedStats['24h'] = [
            'avg_response' => $stats24h->avg_response ? round($stats24h->avg_response) : 0,
            'min_response' => $stats24h->min_response ?? 0,
            'max_response' => $stats24h->max_response ?? 0,
            'total_checks' => $stats24h->total_checks ?? 0,
            'uptime' => $uptime24h,
        ];

        // 7 days stats
        $stats7d = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(7))
            ->selectRaw('AVG(response_time_ms) as avg_response, MIN(response_time_ms) as min_response, MAX(response_time_ms) as max_response, COUNT(*) as total_checks')
            ->first();

        $online7d = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(7))
            ->where('status', 'online')
            ->count();

        $extendedStats['7d'] = [
            'avg_response' => $stats7d->avg_response ? round($stats7d->avg_response) : 0,
            'min_response' => $stats7d->min_response ?? 0,
            'max_response' => $stats7d->max_response ?? 0,
            'total_checks' => $stats7d->total_checks ?? 0,
            'uptime' => $stats7d->total_checks > 0 ? round(($online7d / $stats7d->total_checks) * 100, 2) : 0,
        ];

        // 30 days stats
        $stats30d = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(30))
            ->selectRaw('AVG(response_time_ms) as avg_response, MIN(response_time_ms) as min_response, MAX(response_time_ms) as max_response, COUNT(*) as total_checks')
            ->first();

        $online30d = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(30))
            ->where('status', 'online')
            ->count();

        $extendedStats['30d'] = [
            'avg_response' => $stats30d->avg_response ? round($stats30d->avg_response) : 0,
            'min_response' => $stats30d->min_response ?? 0,
            'max_response' => $stats30d->max_response ?? 0,
            'total_checks' => $stats30d->total_checks ?? 0,
            'uptime' => $stats30d->total_checks > 0 ? round(($online30d / $stats30d->total_checks) * 100, 2) : 0,
        ];

        // 1 year stats
        $stats1y = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subYear())
            ->selectRaw('AVG(response_time_ms) as avg_response, MIN(response_time_ms) as min_response, MAX(response_time_ms) as max_response, COUNT(*) as total_checks')
            ->first();

        $online1y = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subYear())
            ->where('status', 'online')
            ->count();

        $extendedStats['1y'] = [
            'avg_response' => $stats1y->avg_response ? round($stats1y->avg_response) : 0,
            'min_response' => $stats1y->min_response ?? 0,
            'max_response' => $stats1y->max_response ?? 0,
            'total_checks' => $stats1y->total_checks ?? 0,
            'uptime' => $stats1y->total_checks > 0 ? round(($online1y / $stats1y->total_checks) * 100, 2) : 0,
        ];

        // Trend: comparație cu perioada anterioară (pentru 24h, compară cu 24h anterioare)
        $prevStats24h = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(2))
            ->where('checked_at', '<', now()->subDay())
            ->selectRaw('AVG(response_time_ms) as avg_response')
            ->first();

        $trend24h = 0;
        if ($prevStats24h->avg_response && $extendedStats['24h']['avg_response']) {
            $trend24h = round((($extendedStats['24h']['avg_response'] - $prevStats24h->avg_response) / $prevStats24h->avg_response) * 100, 1);
        }
        $extendedStats['24h']['trend'] = $trend24h;

        // Trend pentru 7 zile
        $prevStats7d = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(14))
            ->where('checked_at', '<', now()->subDays(7))
            ->selectRaw('AVG(response_time_ms) as avg_response')
            ->first();

        $trend7d = 0;
        if ($prevStats7d->avg_response && $extendedStats['7d']['avg_response']) {
            $trend7d = round((($extendedStats['7d']['avg_response'] - $prevStats7d->avg_response) / $prevStats7d->avg_response) * 100, 1);
        }
        $extendedStats['7d']['trend'] = $trend7d;
        $extendedStats['30d']['trend'] = 0; // Nu calculăm trend pentru 30d și 1y
        $extendedStats['1y']['trend'] = 0;

        // Uptime pe zile (ultimele 14 zile)
        $uptimeByDay = \App\Models\NameServerStat::where('name_server_id', $nameServer->id)
            ->where('checked_at', '>=', now()->subDays(14))
            ->selectRaw('DATE(checked_at) as date, SUM(CASE WHEN status = "online" THEN 1 ELSE 0 END) as online_checks, COUNT(*) as total_checks')
            ->groupBy('date')
            ->orderBy('date')
            ->get()
            ->toArray();

        return view('admin.nameservers.show', compact(
            'nameServer',
            'stats',
            'chartData24h',
            'chartData7days',
            'chartData30days',
            'chartData1year',
            'uptime24h',
            'extendedStats',
            'uptimeByDay',
            'localZones',
            'powerDNSZones',
            'zoneSearch',
            'totalLocalZones',
            'dnssecStats',
            'incidentHistory'
        ));
    }

    public function edit(NameServer $nameServer)
    {
        return view('admin.nameservers.edit', compact('nameServer'));
    }

    public function update(Request $request, NameServer $nameServer)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'hostname' => 'required|string|unique:name_servers,hostname,' . $nameServer->id,
            'ip_address' => 'required|ip',
            'ipv6_address' => 'nullable|ipv6',
            'api_url' => 'nullable|url',
            'api_key' => 'nullable|string',
            'api_type' => 'required|in:powerdns,bind,custom',
            'api_port' => 'required|integer|min:1|max:65535',
            'server_id' => 'required|string',
            'country_code' => 'nullable|string|size:2',
            'city' => 'nullable|string',
            'region' => 'nullable|in:EU,NA,AS,OC,AF,SA',
            'latitude' => 'nullable|numeric',
            'longitude' => 'nullable|numeric',
            'provider' => 'nullable|string',
            'datacenter' => 'nullable|string',
            'is_active' => 'required|boolean',
            'is_primary' => 'required|boolean',
            'priority' => 'required|integer|min:1|max:100',
            'weight' => 'required|integer|min:1',
            'max_zones' => 'nullable|integer|min:1',
            'description' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        // Conversie explicită pentru boolean-uri (pentru siguranță)
        $validated['is_active'] = (bool) $validated['is_active'];
        $validated['is_primary'] = (bool) $validated['is_primary'];

        $oldData = $nameServer->toArray();
        $nameServer->update($validated);

        // Health check automat după update (dacă s-au schimbat setările API)
        if (isset($validated['api_url']) || isset($validated['api_key']) || isset($validated['api_port'])) {
            try {
                $this->nameServerService->checkHealth($nameServer);
            } catch (\Exception $e) {
                Log::warning("Health check failed for updated NameServer {$nameServer->id}: " . $e->getMessage());
            }
        }

        ActivityLog::log('update', "A actualizat serverul NS: {$nameServer->name}", 'NameServer', $nameServer->id, [
            'old' => $oldData,
            'new' => $nameServer->toArray()
        ]);

        return redirect()->route('admin.nameservers.index')
            ->with('success', 'Serverul NS a fost actualizat cu succes.');
    }

    public function destroy(NameServer $nameServer)
    {
        if ($nameServer->dnsZones()->count() > 0) {
            return redirect()->route('admin.nameservers.index')
                ->with('error', 'Nu poți șterge un server care are zone DNS asociate.');
        }

        $name = $nameServer->name;
        $nameServer->delete();

        ActivityLog::log('delete', "A șters serverul NS: {$name}", 'NameServer', $nameServer->id);

        return redirect()->route('admin.nameservers.index')
            ->with('success', 'Serverul NS a fost șters cu succes.');
    }

    public function testConnection(NameServer $nameServer)
    {
        $result = $this->nameServerService->testConnection($nameServer);

        return response()->json($result);
    }

    public function checkHealth(NameServer $nameServer)
    {
        $result = $this->nameServerService->checkHealth($nameServer);

        return redirect()->back()->with(
            $result['success'] ? 'success' : 'error',
            $result['message']
        );
    }

    public function syncZones(NameServer $nameServer)
    {
        $count = $this->nameServerService->syncAllZones($nameServer);

        return redirect()->back()->with('success', "Au fost sincronizate {$count} zone DNS.");
    }

    /**
     * Comută starea activ/inactiv a serverului
     */
    public function toggleActive(NameServer $nameServer)
    {
        $wasActive = $nameServer->is_active;
        $nameServer->update(['is_active' => !$wasActive]);

        $status = $nameServer->is_active ? 'activat' : 'dezactivat';

        ActivityLog::log(
            'update',
            "A {$status} serverul NS: {$nameServer->name}",
            'NameServer',
            $nameServer->id
        );

        return redirect()->back()->with('success', "Serverul {$nameServer->name} a fost {$status}.");
    }

    /**
     * Căutare AJAX pentru zonele DNS asociate nameserverului
     */
    public function searchZones(Request $request, NameServer $nameServer)
    {
        $search = $request->get('q', '');
        $limit = 5;

        // Caută în zonele locale
        $localZonesQuery = \App\Models\DnsZone::with('user')
            ->where(function($query) use ($nameServer) {
                $query->where('name_server_id', $nameServer->id)
                    ->orWhereJsonContains('allocated_nameservers', $nameServer->id);
            });

        if ($search) {
            $localZonesQuery->where('domain', 'like', "%{$search}%");
        }

        $zones = $localZonesQuery->orderBy('domain')->limit($limit)->get();

        // Formatează rezultatele pentru JSON
        $results = $zones->map(function($zone) {
            return [
                'id' => $zone->id,
                'domain' => $zone->domain,
                'type' => $zone->type,
                'is_active' => $zone->is_active,
                'dnssec_enabled' => $zone->dnssec_enabled,
                'user_name' => $zone->user ? $zone->user->name : null,
                'url' => route('dns-zones.show', $zone),
            ];
        });

        // Numără totalul pentru afișare
        $totalCount = $localZonesQuery->count();

        return response()->json([
            'zones' => $results,
            'total' => $totalCount,
            'showing' => $results->count(),
            'has_more' => $totalCount > $limit,
        ]);
    }
}
