<?php

namespace App\Models;

use App\Notifications\CustomResetPassword;
use App\Notifications\CustomVerifyEmail;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Models\DnsZoneAssignment;
use Laravel\Cashier\Billable;

class User extends Authenticatable implements MustVerifyEmail
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable, Billable;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'role',
        'plan_id',
        'reseller_id',
        'reseller_plan_id',
        'is_active',
        'user_type',
        'first_name',
        'last_name',
        'phone',
        'company_cui',
        'company_name',
        'company_reg_com',
        'company_address',
        'company_number',
        'company_city',
        'company_county',
        'company_postal_code',
        'company_country',
        'terms_accepted',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'two_factor_confirmed_at' => 'datetime',
            'password' => 'hashed',
            'is_active' => 'boolean',
        ];
    }

    /**
     * Relația cu planul de abonament
     */
    public function plan()
    {
        return $this->belongsTo(Plan::class);
    }

    /**
     * Relația cu planul reseller
     */
    public function resellerPlan()
    {
        return $this->belongsTo(ResellerPlan::class);
    }

    /**
     * Relația cu reseller-ul (dacă utilizatorul este client al unui reseller)
     */
    public function reseller()
    {
        return $this->belongsTo(User::class, 'reseller_id');
    }

    /**
     * Relația cu clienții (dacă utilizatorul este reseller)
     */
    public function clients()
    {
        return $this->hasMany(User::class, 'reseller_id');
    }

    /**
     * Relația cu zonele DNS
     */
    public function dnsZones()
    {
        return $this->hasMany(DnsZone::class);
    }

    /**
     * Relația cu utilizarea query-urilor DNS
     */
    public function dnsQueryUsage()
    {
        return $this->hasMany(DnsQueryUsage::class);
    }

    /**
     * Obține utilizarea curentă pentru luna aceasta
     */
    public function getCurrentMonthUsage()
    {
        return DnsQueryUsage::getOrCreateForCurrentMonth($this->id);
    }

    /**
     * Relația cu API tokens
     */
    public function apiTokens()
    {
        return $this->morphMany(ApiToken::class, 'tokenable');
    }

    /**
     * Relația cu DynDNS clients
     */
    public function dynamicDnsClients()
    {
        return $this->hasMany(DynamicDnsClient::class);
    }

    /**
     * Get active API tokens
     */
    public function activeApiTokens()
    {
        return $this->apiTokens()->active();
    }

    /**
     * Check if user can create more API tokens
     */
    public function canCreateApiToken(): bool
    {
        // Admins have unlimited API token creation
        if ($this->isAdmin()) {
            return true;
        }

        if (!$this->plan || !$this->plan->api_enabled) {
            return false;
        }

        $currentTokensCount = $this->apiTokens()->count();
        return $currentTokensCount < $this->plan->api_max_tokens;
    }

    /**
     * Verifică dacă utilizatorul este admin
     */
    public function isAdmin(): bool
    {
        return $this->role === 'admin';
    }

    /**
     * Verifică dacă utilizatorul este reseller
     */
    public function isReseller(): bool
    {
        return $this->role === 'reseller';
    }

    /**
     * Verifică dacă utilizatorul poate adăuga un client nou (pentru reseller)
     */
    public function canAddClient(): bool
    {
        if (!$this->isReseller() || !$this->resellerPlan) {
            return false;
        }

        $currentClients = $this->clients()->count();
        return $currentClients < $this->resellerPlan->max_clients;
    }

    /**
     * Verifică dacă utilizatorul poate adăuga o nouă zonă DNS
     */
    public function canAddDnsZone(): bool
    {
        if ($this->isAdmin()) {
            return true;
        }

        // Numără zonele locale
        $localZones = $this->dnsZones()->count();

        // Numără zonele PowerDNS atribuite
        $powerDnsZones = DnsZoneAssignment::where('user_id', $this->id)->count();

        $totalZones = $localZones + $powerDnsZones;

        // Verifică limita din plan
        if ($this->role === 'reseller' && $this->resellerPlan) {
            // Reseller folosește dns_zones_per_client din planul reseller
            return $totalZones < $this->resellerPlan->dns_zones_per_client;
        } elseif ($this->plan) {
            // Client (fie normal, fie al unui reseller) folosește dns_zones_limit din propriul plan
            return $totalZones < $this->plan->dns_zones_limit;
        }

        return false;
    }

    /**
     * Obține numărul total de înregistrări DNS (locale + PowerDNS)
     */
    public function getTotalRecordsCount(): int
    {
        // Pentru admin, returnează totalul din toată aplicația
        if ($this->isAdmin()) {
            return \App\Models\DnsRecord::count();
        }

        // Numără înregistrările din zone locale
        $localZones = $this->dnsZones;
        $totalRecords = 0;

        foreach ($localZones as $zone) {
            // Pentru zone locale, numără întotdeauna din baza de date locală
            // Aceasta este sursa de adevăr pentru înregistrările utilizatorului
            $totalRecords += $zone->records()->count();
        }

        // Adaugă înregistrările din zone externe (assignments care NU există local)
        $assignments = DnsZoneAssignment::where('user_id', $this->id)->get();

        foreach ($assignments as $assignment) {
            // Verifică dacă zona nu există deja local
            $existsLocally = $localZones->where('domain', rtrim($assignment->zone_name, '.'))->first();

            if (!$existsLocally) {
                // Doar pentru zone care NU există local, numără din PowerDNS
                try {
                    $powerDnsService = app(\App\Services\PowerDNSService::class);
                    $recordsResponse = $powerDnsService->getRecords($assignment->zone_name);

                    if ($recordsResponse['success'] && isset($recordsResponse['data'])) {
                        foreach ($recordsResponse['data'] as $rrset) {
                            $totalRecords += count($rrset['records'] ?? []);
                        }
                    }
                } catch (\Exception $e) {
                    // Ignoră erorile pentru zone externe
                    \Log::warning("Failed to count records for external zone {$assignment->zone_name}: " . $e->getMessage());
                }
            }
        }

        return $totalRecords;
    }

    /**
     * Verifică dacă utilizatorul poate adăuga subdomenii la o zonă
     */
    public function canAddSubdomain(): bool
    {
        if ($this->isAdmin()) {
            return true;
        }

        $totalRecords = $this->getTotalRecordsCount();

        // Verifică limita din plan
        if ($this->role === 'reseller' && $this->resellerPlan) {
            // Reseller folosește subdomains_per_client din planul reseller
            return $totalRecords < $this->resellerPlan->subdomains_per_client;
        } elseif ($this->plan) {
            // Client (fie normal, fie al unui reseller) folosește subdomains_limit din propriul plan
            return $totalRecords < $this->plan->subdomains_limit;
        }

        return false;
    }

    /**
     * Verifică dacă utilizatorul a atins limita de query-uri DNS
     */
    public function hasReachedQueryLimit(): bool
    {
        // Adminii nu au limite
        if ($this->isAdmin()) {
            return false;
        }

        $plan = $this->plan ?? $this->resellerPlan;

        // Dacă nu are plan sau planul e nelimitat
        if (!$plan || !$plan->dns_queries_limit) {
            return false;
        }

        $usage = $this->getCurrentMonthUsage();

        return $usage->query_count >= $plan->dns_queries_limit;
    }

    /**
     * Verifică dacă utilizatorul poate efectua operațiuni DNS
     */
    public function canPerformDnsOperations(): bool
    {
        return !$this->hasReachedQueryLimit();
    }

    /**
     * Obține procentajul de utilizare a query-urilor
     */
    public function getQueryUsagePercentage(): float
    {
        if ($this->isAdmin()) {
            return 0;
        }

        $plan = $this->plan ?? $this->resellerPlan;

        if (!$plan || !$plan->dns_queries_limit) {
            return 0;
        }

        $usage = $this->getCurrentMonthUsage();

        return ($usage->query_count / $plan->dns_queries_limit) * 100;
    }

    /**
     * Trimite notificarea de verificare email folosind șablonul custom
     */
    public function sendEmailVerificationNotification()
    {
        $this->notify(new CustomVerifyEmail);
    }

    /**
     * Trimite notificarea de resetare parolă folosind șablonul custom
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new CustomResetPassword($token));
    }
}
