<?php

namespace App\Livewire;

use App\Jobs\TrackAnalytics;
use App\Models\Domain;
use App\Models\Email;
use App\Models\EmailBody;
use App\Models\Mailbox as MailboxModel;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
use Livewire\Attributes\Layout;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('components.layouts.app')]
class Mailbox extends Component
{
    use WithPagination;

    public $currentMailboxId = null;

    public $activeFolder = 'inbox';

    public $selectedEmailId = null;

    public $search = '';

    public $viewMode = 'text'; // text | html

    public $allowRemoteContent = false;

    // Create State
    public $showCreateModal = false;

    public $createType = 'random'; // random | custom

    public $customUsername = '';

    public $customDomain = '';

    public bool $isCreatingFirstMailbox = false;

    public function mount()
    {
        $this->customDomain = Domain::where('is_active', true)->first()?->name ?? 'imail.app';

        // Load current mailbox from session if exists
        $savedId = Session::get('current_mailbox_id');
        if ($savedId && $this->getActiveMailboxesProperty()->contains('id', $savedId)) {
            $this->currentMailboxId = $savedId;
        } else {
            $this->currentMailboxId = $this->getActiveMailboxesProperty()->first()?->id;
        }

        // Auto-create a random mailbox if none exist (first-time visitor)
        if ($this->getActiveMailboxesProperty()->isEmpty()) {
            $this->isCreatingFirstMailbox = true;
        }
    }

    public function getActiveMailboxesProperty()
    {
        return MailboxModel::query()
            ->where(function ($query) {
                $query->where('session_id', Session::getId());
                if (auth()->check()) {
                    $query->orWhere('user_id', auth()->id());
                }
            })
            ->where('is_blocked', false)
            ->get();
    }

    public function getAvailableDomainsProperty()
    {
        return Domain::query()
            ->where('is_active', true)
            ->where('is_archived', false)
            ->accessibleBy(auth()->user())
            ->get();
    }

    /**
     * Get Reverb/Echo event listeners for the current mailbox domain.
     *
     * @return array<string, string>
     */
    public function getListeners(): array
    {
        $currentMailbox = $this->active_mailboxes->firstWhere('id', $this->currentMailboxId);
        $domain = $currentMailbox ? explode('@', $currentMailbox->address)[1] ?? '' : '';

        if (empty($domain)) {
            return [];
        }

        return [
            "echo:mailbox.{$domain},.new.email" => 'onNewEmail',
        ];
    }

    public function onNewEmail(array $eventData): void
    {
        $sender = ($eventData['sender_name'] ?? null) ?: ($eventData['sender_email'] ?? 'Unknown');
        $subject = ($eventData['subject'] ?? null) ?: '(No Subject)';

        $this->dispatch('notify', 
            message: "Sender: {$sender}\nSubject: {$subject}", 
            type: 'info'
        );

        // Simply refresh the list to pick up the new email from MariaDB
        // Since we order by received_at DESC, it will appear on top.
        $this->dispatch('$refresh');
    }

    public function getEmailsProperty()
    {
        $currentMailbox = $this->active_mailboxes->firstWhere('id', $this->currentMailboxId);

        if (! $currentMailbox) {
            return Email::query()->whereRaw('1 = 0')->paginate(10);
        }

        return Email::query()
            ->where('recipient_email', $currentMailbox->address)
            ->when($this->search, function ($query) {
                $query->where(function ($q) {
                    $q->where('subject', 'like', "%{$this->search}%")
                        ->orWhere('sender_email', 'like', "%{$this->search}%")
                        ->orWhere('sender_name', 'like', "%{$this->search}%");
                });
            })
            ->orderByDesc('received_at')
            ->paginate(10);
    }

    public function getUnreadCountProperty(): int
    {
        $currentMailbox = $this->active_mailboxes->firstWhere('id', $this->currentMailboxId);

        if (! $currentMailbox) {
            return 0;
        }

        return Email::where('recipient_email', $currentMailbox->address)
            ->where('is_read', false)
            ->count();
    }

    public function selectEmail($id)
    {
        $this->selectedEmailId = $id;
        $this->viewMode = 'text';
        $this->allowRemoteContent = false;

        $email = Email::find($id);

        if ($email) {
            if (! $email->is_read) {
                $email->update(['is_read' => true]);
            }

            // Track analytics for reading email
            $currentMailbox = $this->active_mailboxes->firstWhere('id', $this->currentMailboxId);
            if ($currentMailbox) {
                TrackAnalytics::dispatch(
                    eventType: 'email_read',
                    mailboxHash: $currentMailbox->mailbox_hash,
                    domainHash: $currentMailbox->domain_hash,
                    metadata: ['email_id' => $email->id, 'subject' => $email->subject],
                    userId: auth()->id(),
                    userType: auth()->check() ? 'authenticated' : 'guest',
                    ipAddress: request()->ip(),
                    userAgent: request()->userAgent()
                );
            }
        }
    }

    public function switchMailbox($id)
    {
        $this->currentMailboxId = $id;
        $this->selectedEmailId = null;
        $this->search = '';
        $this->resetPage();
        Session::put('current_mailbox_id', $id);

        // Track analytics for switching mailbox
        $currentMailbox = $this->active_mailboxes->firstWhere('id', $id);
        if ($currentMailbox) {
            TrackAnalytics::dispatch(
                eventType: 'mailbox_accessed',
                mailboxHash: $currentMailbox->mailbox_hash,
                domainHash: $currentMailbox->domain_hash,
                userId: auth()->id(),
                userType: auth()->check() ? 'authenticated' : 'guest',
                ipAddress: request()->ip(),
                userAgent: request()->userAgent()
            );

            $currentMailbox->update([
                'last_accessed_at' => now(),
                'last_accessed_ip' => request()->ip(),
            ]);
        }
    }

    public function createMailbox()
    {
        $domainModel = Domain::where('name', $this->customDomain)
            ->where('is_active', true)
            ->accessibleBy(auth()->user())
            ->first();

        if (! $domainModel) {
            return;
        }

        if ($this->createType === 'random') {
            do {
                $address = Str::lower(Str::random(6)).rand(10, 99).'@'.$this->customDomain;
            } while (MailboxModel::withTrashed()->where('address', $address)->exists());
        } else {
            $address = $this->customUsername.'@'.$this->customDomain;

            // Check if address already exists
            $existing = MailboxModel::withTrashed()->where('address', $address)->first();

            if ($existing) {
                // Scenario A: Same User Reclaiming
                $isOwner = (auth()->check() && $existing->user_id === auth()->id())
                        || ($existing->session_id === Session::getId());

                if ($isOwner) {
                    if ($existing->trashed()) {
                        $existing->restore();
                    }
                    if (now() > $existing->expires_at) {
                        $existing->update([
                            'expires_at' => now()->addDays($this->getValidityDays()),
                            'last_accessed_at' => now(),
                        ]);
                    }

                    $this->currentMailboxId = $existing->id;
                    $this->showCreateModal = false;
                    $this->customUsername = '';
                    Session::put('last_mailbox_id', $existing->id);

                    return;
                }

                // Scenario B: Different User Claiming
                if (! $existing->trashed()) {
                    $this->dispatch('notify', message: 'Address already in use.', type: 'danger');

                    return;
                }

                // Address is soft-deleted. Check Tier-based Cooldown
                $user = auth()->user();
                $hoursRequired = match (true) {
                    ! $user => 24, // Guest
                    $user->isEnterprise() || $user->isAdmin() => 0,
                    $user->isPro() => 6,
                    $user->isFree() => 12,
                    default => 12,
                };

                $cooldownEndsAt = $existing->deleted_at->copy()->addHours($hoursRequired);

                if (now()->lessThan($cooldownEndsAt)) {
                    $diff = now()->diff($cooldownEndsAt);
                    $parts = [];
                    if ($diff->d > 0) $parts[] = $diff->d . 'd';
                    if ($diff->h > 0) $parts[] = $diff->h . 'h';
                    if ($diff->i > 0) $parts[] = $diff->i . 'm';
                    if ($diff->s > 0 || empty($parts)) $parts[] = $diff->s . 's';
                    $remaining = implode(' ', $parts);

                    $this->dispatch('notify', message: "Address is in cooldown. Try again in {$remaining}.", type: 'warning');

                    return;
                }

                // Cooldown passed. Permanently delete the old record to sever email history.
                $existing->forceDelete();
            }
        }

        $mailbox = MailboxModel::create([
            'mailbox_hash' => bin2hex(random_bytes(32)),
            'domain_hash' => $domainModel->domain_hash,
            'user_id' => auth()->id(),
            'session_id' => Session::getId(),
            'address' => $address,
            'type' => $this->createType === 'random' ? 'public' : 'custom',
            'created_ip' => request()->ip(),
            'last_accessed_ip' => request()->ip(),
            'last_accessed_at' => now(),
            'expires_at' => now()->addDays($this->getValidityDays()),
        ]);

        $this->currentMailboxId = $mailbox->id;
        $this->showCreateModal = false;
        $this->customUsername = '';
        Session::put('last_mailbox_id', $mailbox->id);
    }

    /**
     * Auto-create a random mailbox on a public domain.
     * Called when no mailboxes exist (first visit, or all deleted).
     */
    public function autoCreateRandomMailbox(): void
    {
        $domain = Domain::query()
            ->where('is_active', true)
            ->where('is_archived', false)
            ->accessibleBy(auth()->user())
            ->whereJsonContains('allowed_types', 'public')
            ->inRandomOrder()
            ->first();

        if (! $domain) {
            return;
        }

        do {
            $address = Str::lower(Str::random(6)).rand(10, 99).'@'.$domain->name;
        } while (MailboxModel::withTrashed()->where('address', $address)->exists());

        $mailbox = MailboxModel::create([
            'mailbox_hash' => bin2hex(random_bytes(32)),
            'domain_hash' => $domain->domain_hash,
            'user_id' => auth()->id(),
            'session_id' => Session::getId(),
            'address' => $address,
            'type' => 'public',
            'created_ip' => request()->ip(),
            'last_accessed_ip' => request()->ip(),
            'last_accessed_at' => now(),
            'expires_at' => now()->addDays($this->getValidityDays()),
        ]);

        $this->currentMailboxId = $mailbox->id;
        $this->isCreatingFirstMailbox = false;
        Session::put('current_mailbox_id', $mailbox->id);
    }

    /**
     * Get mailbox lifespan in days based on user tier.
     * Guest: 1 day, Free: 3 days, Pro: 7 days, Enterprise: 14 days.
     */
    protected function getValidityDays(): int
    {
        $user = auth()->user();

        if (! $user) {
            return 1; // Guests get 24 hours
        }

        return match (true) {
            $user->isEnterprise() => 14,
            $user->isAdmin() => 14, // Assuming admins get enterprise limits
            $user->isPro() => 7,
            $user->isFree() => 3,
            default => 3,
        };
    }

    public function finishAutoCreation(): void
    {
        if ($this->getActiveMailboxesProperty()->isEmpty()) {
            $this->autoCreateRandomMailbox();
        }
        $this->isCreatingFirstMailbox = false;

        // Ensure the component re-renders fully with the new data
        $this->dispatch('$refresh');
    }

    public function deleteMailbox($id)
    {
        $mailbox = MailboxModel::find($id);
        if ($mailbox) {
            $mailbox->delete();
        }

        if ($this->currentMailboxId === $id) {
            $this->currentMailboxId = $this->active_mailboxes->first()?->id;
            $this->selectedEmailId = null;
            session(['current_mailbox_id' => $this->currentMailboxId]);
        }

        // If all mailboxes deleted, auto-create a new random one
        // Use a direct query or re-fetch the property to avoid cache issues
        $hasActive = MailboxModel::query()
            ->where(function ($query) {
                $query->where('session_id', Session::getId());
                if (auth()->check()) {
                    $query->orWhere('user_id', auth()->id());
                }
            })
            ->where('is_blocked', false)
            ->exists();

        if (! $hasActive) {
            $this->isCreatingFirstMailbox = true;
        }
    }

    public function downloadEmail($id)
    {
        // Mock download logic
        $this->js("alert('Downloading email #{$id}... (Mock Action)')");
    }

    public function printEmail($id)
    {
        // Mock print logic
        $this->js('window.print()');
    }

    public function deleteEmail($id)
    {
        // Mock delete logic
        $this->js("alert('Email #{$id} deleted successfully! (Mock Action)')");
        $this->selectedEmailId = null;
    }

    public function nextPage()
    {
        if ($this->page < $this->totalPages) {
            $this->page++;
            $this->selectedEmailId = null;
        }
    }

    public function previousPage()
    {
        if ($this->page > 1) {
            $this->page--;
            $this->selectedEmailId = null;
        }
    }

    public function generateQrCode($address)
    {
        // Mock QR generation with a slight delay
        usleep(800000); // 800ms
        $this->dispatch('qrCodeGenerated', address: $address);
    }

    public function getProcessedContent($email)
    {
        $body = EmailBody::where('unique_id_hash', $email->unique_id_hash)->first();

        if (! $body) {
            return 'Email body not found.';
        }

        $content = $body->body_html ?? $body->body_text;
        $isText = $this->viewMode === 'text';

        // Fallback to HTML if text is selected but body_text is empty
        if ($isText && ! empty($body->body_text)) {
            return trim(e($body->body_text));
        }

        if ($isText) {
            // If fallback occurred, we sanitize the HTML to text
            return trim(strip_tags($content));
        }

        if (! $this->allowRemoteContent) {
            // Block remote assets by replacing src with data-src for img tags
            return preg_replace('/<img\s[^>]*?\bsrc\s*=\s*([\'"])(.*?)\1/i', '<img $2 data-blocked-src=$1$2$1 src="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 1 1\'%3E%3C/svg%3E" class="blocked-remote-asset shadow-sm border border-white/5 opacity-50"', $content);
        }

        return $content;
    }

    public function render()
    {
        $currentMailbox = $this->active_mailboxes->firstWhere('id', $this->currentMailboxId);

        return view('livewire.mailbox', [
            'emails' => $this->getEmailsProperty(),
            'currentMailbox' => $currentMailbox,
            'unreadCount' => $this->unread_count,
        ]);
    }
}
