<?php

namespace App\Models;

use App\Services\PowerDNSService;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;

class DnsZone extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'name_server_id',
        'domain',
        'type',
        'is_active',
        'sync_to_powerdns',
        'powerdns_zone_id',
        'is_powerdns_synced',
        'dnssec_enabled',
        'allocated_nameservers',
    ];

    protected function casts(): array
    {
        return [
            'is_active' => 'boolean',
            'sync_to_powerdns' => 'boolean',
            'is_powerdns_synced' => 'boolean',
            'dnssec_enabled' => 'boolean',
            'allocated_nameservers' => 'array',
        ];
    }

    /**
     * Folosește domeniul ca route key în loc de ID
     */
    public function getRouteKeyName()
    {
        return 'domain';
    }

    /**
     * Boot method pentru evenimente model
     */
    protected static function boot()
    {
        parent::boot();

        // Când se creează o zonă nouă, o sincronizăm cu PowerDNS
        static::created(function (DnsZone $zone) {
            $zone->syncToPowerDNS();
        });

        // Când se actualizează o zonă, o sincronizăm cu PowerDNS
        static::updated(function (DnsZone $zone) {
            if ($zone->is_powerdns_synced) {
                $zone->syncToPowerDNS();
            }
        });

        // Când se șterge o zonă, o ștergem și din PowerDNS
        static::deleted(function (DnsZone $zone) {
            if ($zone->is_powerdns_synced && $zone->powerdns_zone_id) {
                $zone->deleteFromPowerDNS();
            }
        });
    }

    /**
     * Relația cu utilizatorul
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Relația cu serverul Name Server (legacy - pentru compatibilitate)
     */
    public function nameServer()
    {
        return $this->belongsTo(NameServer::class);
    }

    /**
     * Relația many-to-many cu nameserverele (nou sistem)
     */
    public function nameServers()
    {
        return $this->belongsToMany(NameServer::class, 'dns_zone_nameserver')
            ->withPivot('powerdns_zone_id', 'is_synced', 'last_synced_at')
            ->withTimestamps();
    }

    /**
     * Obține doar nameserverele pe care zona este sincronizată
     */
    public function syncedNameServers()
    {
        return $this->nameServers()->wherePivot('is_synced', true);
    }

    /**
     * Relația cu înregistrările DNS
     */
    public function records()
    {
        return $this->hasMany(DnsRecord::class);
    }

    /**
     * Relația cu statisticile DNS
     */
    public function statistics()
    {
        return $this->hasMany(DnsStatistic::class);
    }

    /**
     * Relația cu zona Cloudflare (dacă există)
     */
    public function cloudflareZone()
    {
        return $this->hasOne(CloudflareZone::class, 'dns_zone_id');
    }

    /**
     * Verifică dacă zona este conectată la Cloudflare
     */
    public function isCloudflareZone(): bool
    {
        return $this->cloudflareZone()->exists();
    }

    /**
     * Relația cu alertele DNS
     */
    public function alerts()
    {
        return $this->hasMany(DnsZoneAlert::class);
    }

    /**
     * Verifică dacă zona are alerte active
     */
    public function hasActiveAlerts(): bool
    {
        return $this->alerts()->where('is_resolved', false)->exists();
    }

    /**
     * Obține alerta activă pentru nameservere
     */
    public function getActiveNameserverAlert()
    {
        return $this->alerts()
            ->where('alert_type', 'nameserver_misconfigured')
            ->where('is_resolved', false)
            ->first();
    }

    /**
     * Verifică dacă zona este suspendată
     */
    public function isSuspended(): bool
    {
        return !is_null($this->suspended_at);
    }

    /**
     * Verifică dacă zona poate fi reactivată
     */
    public function canBeReactivated(): bool
    {
        return $this->isSuspended() && $this->can_be_reactivated;
    }

    /**
     * Obține numărul de înregistrări DNS active
     */
    public function activeRecordsCount(): int
    {
        return $this->records()->where('is_active', true)->count();
    }

    /**
     * Verifică dacă zona este activă
     */
    public function isActive(): bool
    {
        return $this->is_active;
    }

    /**
     * Sincronizează zona cu PowerDNS
     */
    public function syncToPowerDNS(): array
    {
        // Verifică dacă zona are name server atribuit
        if (!$this->nameServer) {
            \Log::warning('Cannot sync zone to PowerDNS: no name server assigned', ['zone' => $this->domain]);
            return [
                'success' => false,
                'message' => 'Zona nu are un name server atribuit'
            ];
        }

        try {
            // Folosește API-ul name server-ului specific
            $powerDNS = new PowerDNSService(
                $this->nameServer->api_url,
                $this->nameServer->api_key
            );

            // Verifică dacă zona există deja în PowerDNS
            $zoneName = rtrim($this->domain, '.') . '.'; // Asigură că se termină cu punct
            $zoneCheck = $powerDNS->getZone($zoneName);

            if (!$zoneCheck['success']) {
                // Zona nu există, o creăm
                $zoneData = [
                    'name' => $zoneName,
                    'kind' => 'Native',
                    'nameservers' => [
                        'ns1.gazduiredns.ro.',
                        'ns2.gazduiredns.ro.'
                    ],
                    'rrsets' => [
                        [
                            'name' => $zoneName,
                            'type' => 'SOA',
                            'ttl' => 3600,
                            'records' => [
                                [
                                    'content' => 'ns1.gazduiredns.ro. admin.' . $zoneName . ' 2023110201 10800 3600 604800 86400',
                                    'disabled' => false
                                ]
                            ]
                        ]
                    ]
                ];

                $createResult = $powerDNS->createZone($zoneData);

                if ($createResult['success']) {
                    $this->powerdns_zone_id = $zoneName;
                    $this->is_powerdns_synced = true;
                    $this->saveQuietly(); // Salvăm fără să declanșăm din nou evenimentele

                    Log::info("Zona {$this->domain} sincronizată cu PowerDNS");

                    return [
                        'success' => true,
                        'message' => 'Zona a fost creată și sincronizată cu succes'
                    ];
                } else {
                    return [
                        'success' => false,
                        'message' => $createResult['message'] ?? 'Eroare la crearea zonei în PowerDNS'
                    ];
                }
            } else {
                // Zona există deja, marcăm ca sincronizată
                $this->powerdns_zone_id = $zoneName;
                $this->is_powerdns_synced = true;
                $this->saveQuietly();
            }

            // Sincronizează toate record-urile active din DB local către PowerDNS
            $recordsSynced = 0;
            $recordsErrors = 0;

            $activeRecords = $this->records()->where('is_active', true)->get();

            foreach ($activeRecords as $record) {
                try {
                    // Construiește numele complet pentru PowerDNS
                    $recordName = $record->name;
                    if ($recordName === '@') {
                        $fullName = $zoneName;
                    } else {
                        $fullName = $recordName . '.' . $zoneName;
                    }

                    // Construiește content-ul
                    $content = $record->content;

                    // Pentru MX, adaugă priority
                    if ($record->type === 'MX' && $record->priority) {
                        $content = $record->priority . ' ' . $content;
                    }

                    // Adaugă punct final pentru FQDN dacă este necesar
                    if (in_array($record->type, ['CNAME', 'NS', 'PTR', 'SRV', 'MX']) &&
                        !str_ends_with($content, '.') &&
                        !filter_var($content, FILTER_VALIDATE_IP)) {
                        $content .= '.';
                    }

                    // Sincronizează record-ul
                    $rrsetData = [
                        'rrsets' => [
                            [
                                'name' => $fullName,
                                'type' => $record->type,
                                'ttl' => $record->ttl,
                                'changetype' => 'REPLACE',
                                'records' => [
                                    [
                                        'content' => $content,
                                        'disabled' => false
                                    ]
                                ]
                            ]
                        ]
                    ];

                    $updateResult = $powerDNS->updateZone($zoneName, $rrsetData);

                    if ($updateResult['success']) {
                        $recordsSynced++;
                    } else {
                        $recordsErrors++;
                        \Log::warning("Failed to sync record {$fullName} ({$record->type}): " . ($updateResult['message'] ?? 'Unknown error'));
                    }

                } catch (\Exception $e) {
                    $recordsErrors++;
                    \Log::error("Error syncing record {$record->name} ({$record->type}): " . $e->getMessage());
                }
            }

            $message = "Zona sincronizată cu succes";
            if ($recordsSynced > 0) {
                $message .= ". {$recordsSynced} record(uri) sincronizate";
            }
            if ($recordsErrors > 0) {
                $message .= ". {$recordsErrors} erori la sincronizare records";
            }

            return [
                'success' => true,
                'message' => $message,
                'records_synced' => $recordsSynced,
                'records_errors' => $recordsErrors
            ];

        } catch (\Exception $e) {
            Log::error("Eroare sincronizare PowerDNS pentru zona {$this->domain}: " . $e->getMessage());

            return [
                'success' => false,
                'message' => $e->getMessage()
            ];
        }
    }

    /**
     * Șterge zona din PowerDNS
     */
    public function deleteFromPowerDNS(): bool
    {
        // Verifică dacă zona are name server atribuit
        if (!$this->nameServer) {
            \Log::warning('Cannot delete zone from PowerDNS: no name server assigned', ['zone' => $this->domain]);
            return false;
        }

        try {
            // Folosește API-ul name server-ului specific
            $powerDNS = new PowerDNSService(
                $this->nameServer->api_url,
                $this->nameServer->api_key
            );
            $zoneName = $this->domain . '.';
            $result = $powerDNS->deleteZone($zoneName);

            if ($result['success']) {
                Log::info("Zona {$this->domain} ștearsă din PowerDNS");
                return true;
            }
        } catch (\Exception $e) {
            Log::error("Eroare ștergere PowerDNS pentru zona {$this->domain}: " . $e->getMessage());
        }

        return false;
    }

    /**
     * Obține înregistrările DNS de la PowerDNS
     */
    public function getPowerDNSRecords(): array
    {
        if (!$this->is_powerdns_synced || !$this->powerdns_zone_id) {
            return [];
        }

        // Verifică dacă zona are name server atribuit
        if (!$this->nameServer) {
            return [];
        }

        try {
            // Folosește API-ul name server-ului specific
            $powerDNS = new PowerDNSService(
                $this->nameServer->api_url,
                $this->nameServer->api_key
            );
            $zoneName = $this->domain . '.';
            $result = $powerDNS->getZone($zoneName);

            if ($result['success']) {
                return $result['data']['rrsets'] ?? [];
            }
        } catch (\Exception $e) {
            Log::error("Eroare obținere înregistrări PowerDNS pentru zona {$this->domain}: " . $e->getMessage());
        }

        return [];
    }

    /**
     * Verifică dacă zona este sincronizată cu PowerDNS
     */
    public function isPowerDNSSynced(): bool
    {
        return $this->is_powerdns_synced;
    }
}
