<?php

namespace App\Http\Controllers;

use App\Models\EmailFolder;
use App\Models\EmailMessage;
use App\Models\EmailAttachment;
use App\Models\EmailSetting;
use App\Models\SenderAccount;
use App\Models\MailingList;
use App\Models\Gruppo;
use App\Models\Individuo;
use App\Models\Documento;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class EmailController extends Controller
{
    public function index(Request $request, $folder = 'inbox')
    {
        $this->authorizeRead('email');
        if ($folder === 'compose' || $folder === 'nuovo') {
            return $this->compose($request);
        }
        
        $folderModel = EmailFolder::where('type', $folder)->first();
        
        if (!$folderModel) {
            $folderModel = EmailFolder::where('type', 'inbox')->first();
            if (!$folderModel) {
                $this->ensureFoldersExist();
                $folderModel = EmailFolder::where('type', 'inbox')->first();
            }
        }

        $query = EmailMessage::where('email_folder_id', $folderModel->id);
        
        if ($request->search) {
            $query->where(function ($q) use ($request) {
                $q->where('subject', 'like', '%' . $request->search . '%')
                  ->orWhere('from_email', 'like', '%' . $request->search . '%')
                  ->orWhere('to_email', 'like', '%' . $request->search . '%')
                  ->orWhere('body_text', 'like', '%' . $request->search . '%');
            });
        }

        $sortField = $request->sort ?? 'received_at';
        $sortDir = $request->direction ?? 'desc';
        
        $allowedSorts = ['subject', 'received_at', 'sent_at', 'from_email', 'to_email'];
        if (!in_array($sortField, $allowedSorts)) {
            $sortField = 'received_at';
        }
        if (!in_array($sortDir, ['asc', 'desc'])) {
            $sortDir = 'desc';
        }
        
        $query->orderBy($sortField === 'sent_at' ? 'received_at' : $sortField, $sortDir);

        $messages = $query->paginate(20)->withQueryString();
        $folders = EmailFolder::orderBy('sort_order')->get();
        $mailingLists = MailingList::where('attiva', true)->get();
        $gruppi = Gruppo::orderBy('nome')->get();
        
        $emailSettings = EmailSetting::getActive();
        $syncInterval = $emailSettings ? $emailSettings->sync_interval_minutes : 0;

        return view('email.index', compact('messages', 'folders', 'folder', 'folderModel', 'mailingLists', 'gruppi', 'syncInterval'));
    }

    public function show($folder, $id)
    {
        $this->authorizeRead('email');
        $message = EmailMessage::with('attachments')->findOrFail($id);
        
        if (!$message->is_read) {
            $message->update(['is_read' => true]);
        }

        $folders = EmailFolder::orderBy('sort_order')->get();
        
        return view('email.show', compact('message', 'folders', 'folder'));
    }

    public function compose(Request $request)
    {
        $this->authorizeWrite('email');
        $folders = EmailFolder::orderBy('sort_order')->get();
        $mailingLists = MailingList::where('attiva', true)->get();
        $gruppi = Gruppo::orderBy('nome')->get();
        $individui = Individuo::orderBy('cognome')->orderBy('nome')->get();
        $senderAccounts = SenderAccount::active()->get();

        $prefill = [];
        if ($request->reply_to) {
            $original = EmailMessage::find($request->reply_to);
            if ($original) {
                $prefill['to'] = $original->from_email;
                $prefill['subject'] = 'Re: ' . $original->subject;
                $prefill['body'] = "\n\n--- Messaggio originale ---\n" . ($original->body_text ?? $original->body_html);
            }
        }
        if ($request->forward) {
            $original = EmailMessage::find($request->forward);
            if ($original) {
                $prefill['subject'] = 'Fwd: ' . $original->subject;
                $prefill['body'] = "\n\n--- Messaggio inoltrato ---\n" . ($original->body_text ?? $original->body_html);
            }
        }

        return view('email.compose', compact('folders', 'mailingLists', 'gruppi', 'individui', 'prefill', 'senderAccounts'));
    }

    public function send(Request $request)
    {
        $this->authorizeWrite('email');
        $rules = [
            'subject' => 'required',
            'body' => 'required',
        ];
        
        if ($request->destinatario_tipo === 'manuale' || !$request->destinatario_tipo) {
            $rules['to'] = 'required';
        }
        
        $validated = $request->validate($rules);

        $recipients = $this->resolveRecipients($request);
        
        \Illuminate\Support\Facades\Log::info('Email send attempt', [
            'recipients' => $recipients,
            'recipients_count' => count($recipients),
            'subject' => $validated['subject'],
            'destinatario_tipo' => $request->destinatario_tipo,
            'mittente_id' => $request->mittente_id,
        ]);
        
        if (empty($recipients)) {
            return back()->with('error', 'Nessun destinatario trovato. Seleziona almeno un destinatario dal menu a tendina o inserisci un indirizzo email manuale.')->withInput();
        }

        $useSender = $request->filled('mittente_id') && $request->mittente_id > 0;

        if ($useSender) {
            return $this->sendWithSender($request, $validated, $recipients);
        }

        $settings = EmailSetting::getActive();
        if (!$settings) {
            return back()->with('error', 'Account email non configurato.');
        }

        $imapSuccess = false;
        $imapError = null;
        $attachments = $this->processAttachments($request);

        foreach ($recipients as $recipient) {
            try {
                $bodyWithSig = $this->appendSignature($validated['body'], $settings->getSignature(), $settings->signature_enabled ?? false);
                $this->sendViaImap($settings, $recipient, $validated['subject'], $bodyWithSig, $request->cc, $attachments);
                $imapSuccess = true;
            } catch (\Exception $e) {
                $imapError = $e->getMessage();
                \Illuminate\Support\Facades\Log::error('SMTP send error', ['error' => $e->getMessage()]);
            }
        }

        try {
            $bodyWithSig = $this->appendSignature($validated['body'], $settings->getSignature(), $settings->signature_enabled ?? false);
            $this->storeSentMessage($settings, $recipients, $validated['subject'], $bodyWithSig, $request->cc);
        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('Store sent message error', ['error' => $e->getMessage()]);
            return back()->with('error', 'Errore nel salvataggio: ' . $e->getMessage())->withInput();
        }

        if (!$imapSuccess && $imapError) {
            return redirect()->route('email.index', 'sent')->with('warning', 'Email salvata in Invio ma non inviata via SMTP: ' . $imapError);
        }

        return redirect()->route('email.index', 'sent')->with('success', 'Email inviata con successo.');
    }

    private function sendWithSender(Request $request, array $validated, array $recipients)
    {
        $sender = SenderAccount::findOrFail($request->mittente_id);
        $attachmentPaths = $this->resolveAttachmentPaths($request);
        $ok = 0;
        $errors = [];

        foreach ($recipients as $recipient) {
            try {
                $sender->sendEmail($recipient, $validated['subject'], $validated['body'], $attachmentPaths);
                $ok++;
            } catch (\Exception $e) {
                $errors[] = $recipient . ': ' . $e->getMessage();
            }
        }

        if ($sender->verify_email) {
            $reportSubject = '✅ Invio: ' . $validated['subject'] . ' - ' . $sender->email_address;
            $reportBody = "Report invio mittente: {$sender->email_address}\n"
                . "Destinatari totali: " . count($recipients) . "\n"
                . "Inviate con successo: {$ok}\n"
                . "Fallite: " . count($errors) . "\n";
            if (!empty($errors)) {
                $reportBody .= "\nDettaglio errori:\n" . implode("\n", $errors);
            }
            $sender->sendReport($reportSubject, $reportBody);
        }

        if ($ok === 0 && !empty($errors)) {
            return redirect()->route('email.index', 'sent')->with('error', 'Invio fallito: ' . implode('; ', $errors));
        }

        $message = $ok . ' email inviate con successo tramite "' . $sender->email_address . '".';
        if (!empty($errors)) {
            $message .= ' ' . count($errors) . ' fallite.';
        }

        return redirect()->route('email.index', 'sent')->with('success', $message);
    }

    public function storeDraft(Request $request)
    {
        $this->authorizeWrite('email');
        $settings = EmailSetting::getActive();
        $folder = EmailFolder::where('type', 'drafts')->first();

        $message = EmailMessage::create([
            'email_folder_id' => $folder->id,
            'subject' => $request->subject ?? '(senza oggetto)',
            'body_text' => $request->body,
            'to_email' => $request->to,
            'is_draft' => true,
            'from_email' => $settings->email_address ?? '',
            'from_name' => $settings->email_name ?? '',
        ]);

        return response()->json(['success' => true, 'draft_id' => $message->id]);
    }

    public function bulkAction(Request $request)
    {
        try {
            $this->authorizeWrite('email');
        } catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Non hai i permessi per questa azione'
            ], 403);
        }
        
        $ids = $request->input('ids', []);
        $action = $request->input('action');
        
        if ($action === 'empty_trash') {
            $trashFolder = EmailFolder::where('type', 'trash')->first();
            if ($trashFolder) {
                EmailMessage::where('email_folder_id', $trashFolder->id)->delete();
            }
            return response()->json(['success' => true]);
        }
        
        if (empty($ids)) {
            return response()->json(['success' => false, 'message' => 'Nessuna email selezionata']);
        }
        
        $messages = EmailMessage::whereIn('id', $ids)->get();
        
        switch ($action) {
            case 'mark_read':
                $messages->each->update(['is_read' => true]);
                break;
            case 'mark_unread':
                $messages->each->update(['is_read' => false]);
                break;
            case 'star':
                $messages->each->update(['is_starred' => true]);
                break;
            case 'unstar':
                $messages->each->update(['is_starred' => false]);
                break;
            case 'move_trash':
                $trashFolder = EmailFolder::where('type', 'trash')->first();
                if ($trashFolder) {
                    $messages->each->update(['email_folder_id' => $trashFolder->id]);
                }
                break;
            case 'delete_permanent':
                $messages->each->delete();
                break;
            default:
                return response()->json(['success' => false, 'message' => 'Azione non valida']);
        }
        
        return response()->json(['success' => true]);
    }

    public function markRead($id)
    {
        try {
            $this->authorizeWrite('email');
        } catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Non hai i permessi per questa azione'
            ], 403);
        }
        $message = EmailMessage::findOrFail($id);
        $message->update(['is_read' => true]);
        return response()->json(['success' => true]);
    }

    public function toggleStar($id)
    {
        try {
            $this->authorizeWrite('email');
        } catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) {
            return response()->json([
                'success' => false,
                'message' => 'Non hai i permessi per questa azione'
            ], 403);
        }
        $message = EmailMessage::findOrFail($id);
        $message->update(['is_starred' => !$message->is_starred]);
        return response()->json(['success' => true, 'is_starred' => $message->is_starred]);
    }

    public function destroy($id)
    {
        $this->authorizeDelete('email');
        $message = EmailMessage::findOrFail($id);
        $trashFolder = EmailFolder::where('type', 'trash')->first();
        
        if ($trashFolder) {
            $message->update(['is_trash' => true, 'email_folder_id' => $trashFolder->id]);
        } else {
            $message->delete();
        }

        return back()->with('success', 'Email spostata nel cestino.');
    }

    public function downloadAttachment($id)
    {
        $this->authorizeRead('email');
        $attachment = EmailAttachment::findOrFail($id);
        
        if (!Storage::exists($attachment->file_path)) {
            abort(404);
        }

        return Storage::download($attachment->file_path, $attachment->filename);
    }

    public function saveAttachmentToDocumenti(Request $request, $id, $attachmentId)
    {
        $this->authorizeWrite('email');
        $this->authorizeWrite('documenti');
        $attachment = EmailAttachment::findOrFail($attachmentId);
        
        $documento = Documento::create([
            'nome_file' => $attachment->filename,
            'file_path' => $attachment->file_path,
            'tipo' => 'upload',
            'tipologia' => 'email_attachment',
            'mime_type' => $attachment->mime_type,
            'dimensione' => $attachment->size,
            'visibilita' => null,
            'note' => 'Allegato email: ' . ($attachment->message->subject ?? ''),
        ]);

        $attachment->update(['is_saved_to_documenti' => true, 'documenti_id' => $documento->id]);

        return back()->with('success', 'Allegato salvato nei documenti.');
    }

    public function quickSync()
    {
        try {
            $this->syncEmails();
            return response()->json(['success' => true, 'message' => 'Sincronizzazione completata']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()]);
        }
    }

    public function syncEmails()
    {
        \Illuminate\Support\Facades\Log::info('Email sync started');

        $settings = EmailSetting::getActive();
        if (!$settings) {
            \Illuminate\Support\Facades\Log::warning('Email sync aborted: no active email configuration');
            throw new \Exception('Nessuna configurazione email attiva');
        }

        $this->ensureFoldersExist();

        $mailbox = $this->connectImap($settings);
        
        \Illuminate\Support\Facades\Log::info('IMAP connection established', ['host' => $settings->imap_host]);

        $folderMappings = [
            'INBOX' => 'inbox',
            'Sent' => 'sent',
            '[Gmail]/Sent Mail' => 'sent',
            'Sent Mail' => 'sent',
            'Drafts' => 'drafts',
            '[Gmail]/Drafts' => 'drafts',
            'Trash' => 'trash',
            '[Gmail]/Trash' => 'trash',
        ];

        $totalProcessed = 0;
        $totalNew = 0;

        foreach (array_keys($folderMappings) as $imapFolderName) {
            try {
                $folder = $mailbox->folders()->find($imapFolderName);
                if (!$folder) {
                    \Illuminate\Support\Facades\Log::debug('IMAP folder not found', ['folder' => $imapFolderName]);
                    continue;
                }
                
                \Illuminate\Support\Facades\Log::info('Processing IMAP folder', ['folder' => $imapFolderName]);

                $messages = $folder->messages()
                    ->withHeaders()
                    ->withBody()
                    ->withBodyStructure()
                    ->limit(100)
                    ->get();
                
                \Illuminate\Support\Facades\Log::info('Messages fetched from folder', ['folder' => $imapFolderName, 'count' => count($messages)]);

                foreach ($messages as $imapMessage) {
                    $totalProcessed++;
                    $messageId = $imapMessage->messageId() ?? uniqid('msg_');
                    $existing = EmailMessage::where('message_id', $messageId)->first();
                    
                    if ($existing) {
                        continue;
                    }

                    $this->processImapMessage($imapMessage, $imapFolderName);
                    $totalNew++;
                }
            } catch (\Exception $e) {
                \Illuminate\Support\Facades\Log::error('Error processing IMAP folder', ['folder' => $imapFolderName, 'error' => $e->getMessage()]);
                continue;
            }
        }

        \Illuminate\Support\Facades\Log::info('Email sync completed', [
            'processed' => $totalProcessed,
            'new' => $totalNew,
        ]);

        return true;
    }

    private function resolveRecipients(Request $request)
    {
        $recipients = [];

        if ($request->destinatario_tipo === 'individui' && $request->individui) {
            $individui = Individuo::whereIn('id', $request->individui)->get();
            foreach ($individui as $ind) {
                $emails = $ind->contatti()->where('tipo', 'email')->pluck('valore')->toArray();
                $recipients = array_merge($recipients, $emails);
            }
        } elseif ($request->destinatario_tipo === 'gruppo' && $request->gruppo_id) {
            $gruppo = Gruppo::with('individui.contatti')->find($request->gruppo_id);
            foreach ($gruppo->individui as $ind) {
                $emails = $ind->contatti()->where('tipo', 'email')->pluck('valore')->toArray();
                $recipients = array_merge($recipients, $emails);
            }
        } elseif ($request->destinatario_tipo === 'mailing_list' && $request->mailing_list_id) {
            $list = MailingList::with('contatti.individuo')->find($request->mailing_list_id);
            foreach ($list->contatti as $contact) {
                if ($contact->opt_in && $contact->individuo) {
                    $emails = $contact->individuo->contatti()->where('tipo', 'email')->pluck('valore')->toArray();
                    $recipients = array_merge($recipients, $emails);
                }
            }
        } elseif ($request->to) {
            $recipients = is_array($request->to) ? $request->to : [$request->to];
        }

        return array_filter(array_unique($recipients));
    }

    private function appendSignature(string $body, ?string $signature, bool $enabled): string
    {
        if (empty($signature) || !$enabled) {
            return $body;
        }
        return $body . "\n\n---\n" . $signature;
    }

    private function sendViaImap($settings, $to, $subject, $body, $cc = null, array $attachmentPaths = [])
    {
        \Illuminate\Support\Facades\Log::info('sendViaSMTP start', ['to' => $to, 'subject' => $subject]);
        
        $smtpPassword = $settings->getDecryptedSmtpPassword() ?? $settings->getDecryptedPassword();
        
        $encryption = $settings->smtp_encryption ?? 'tls';
        $scheme = ($encryption === 'ssl') ? 'smtps' : 'smtp';
        
        $dsn = sprintf(
            '%s://%s:%s@%s:%d?encryption=%s',
            $scheme,
            rawurlencode($settings->smtp_username ?? $settings->email_address),
            rawurlencode($smtpPassword),
            $settings->smtp_host ?? 'smtp.gmail.com',
            $settings->smtp_port ?? 587,
            $encryption
        );
        
        try {
            $transport = \Symfony\Component\Mailer\Transport::fromDsn($dsn);
            $mailer = new \Symfony\Component\Mailer\Mailer($transport);
            
            $fromName = $settings->email_name ?? '';
            if (filter_var($fromName, FILTER_VALIDATE_EMAIL)) {
                $fromName = 'Glastree';
            } else {
                $fromName = preg_replace('/[^\p{L}\p{N}\s]/u', '', $fromName);
                $fromName = trim($fromName);
                if (empty($fromName)) {
                    $fromName = 'Glastree';
                }
            }

            $fromAddress = \Symfony\Component\Mime\Address::create($settings->email_address, $fromName);

            $email = (new \Symfony\Component\Mime\Email())
                ->from($fromAddress)
                ->to($to)
                ->subject($subject)
                ->text($body);
            
            if ($cc) {
                $email->cc($cc);
            }

            foreach ($attachmentPaths as $attachmentPath) {
                $email->attachFromPath($attachmentPath);
            }
            
            $mailer->send($email);
            
            \Illuminate\Support\Facades\Log::info('Email sent via SMTP successfully');
            return true;
        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('SMTP send error', ['error' => $e->getMessage()]);
            throw new \Exception('Errore invio SMTP: ' . $e->getMessage());
        }
    }

    private function processAttachments(Request $request): array
    {
        $paths = [];
        if ($request->hasFile('allegati')) {
            foreach ($request->file('allegati') as $file) {
                if ($file->isValid()) {
                    $paths[] = $file->getRealPath();
                }
            }
        }
        return $paths;
    }

    private function resolveAttachmentPaths(Request $request): array
    {
        $paths = [];

        if ($request->hasFile('allegati')) {
            foreach ($request->file('allegati') as $file) {
                if ($file->isValid()) {
                    $paths[] = $file->getRealPath();
                }
            }
        }

        $documentIds = $request->input('documenti_selezionati');
        if (!empty($documentIds)) {
            $ids = is_array($documentIds) ? $documentIds : explode(',', $documentIds);
            $docs = Documento::whereIn('id', $ids)->get();
            foreach ($docs as $doc) {
                if ($doc->file_path && \Illuminate\Support\Facades\Storage::exists($doc->file_path)) {
                    $paths[] = \Illuminate\Support\Facades\Storage::path($doc->file_path);
                }
            }
        }

        return $paths;
    }

    private function storeSentMessage($settings, $recipients, $subject, $body, $cc = null)
    {
        $sentFolder = EmailFolder::where('type', 'sent')->first();
        $bodyWithSignature = $this->appendSignature($body, $settings->getSignature(), $settings->signature_enabled ?? false);
        
        $message = EmailMessage::create([
            'email_folder_id' => $sentFolder->id,
            'subject' => $subject,
            'body_text' => $bodyWithSignature,
            'from_email' => $settings->email_address,
            'from_name' => $settings->email_name,
            'to_email' => implode(', ', $recipients),
            'cc' => $cc,
            'is_sent' => true,
            'sent_at' => now(),
            'is_read' => true,
        ]);

        return $message;
    }

    private function connectImap($settings)
    {
        if (!$settings->imap_host || !$settings->imap_username) {
            throw new \Exception('Configurazione IMAP non valida');
        }

        $encryption = match ($settings->imap_encryption) {
            'ssl' => 'ssl',
            'tls' => 'tls',
            default => 'none',
        };

        return new \DirectoryTree\ImapEngine\Mailbox([
            'host' => $settings->imap_host,
            'port' => $settings->imap_port ?? 993,
            'encryption' => $encryption,
            'validate_cert' => false,
            'username' => $settings->imap_username,
            'password' => $settings->getDecryptedPassword(),
        ]);
    }

    private function processImapMessage($imapMessage, $imapFolder)
    {
        $folderType = match ($imapFolder) {
            'INBOX', 'inbox' => 'inbox',
            'Sent', 'sent', '[Gmail]/Sent Mail' => 'sent',
            'Drafts', 'drafts', '[Gmail]/Drafts' => 'drafts',
            'Trash', 'trash', '[Gmail]/Trash' => 'trash',
            'Archive', 'archive', '[Gmail]/All Mail' => 'archive',
            'Starred', 'starred', '[Gmail]/Starred' => 'starred',
            default => 'inbox',
        };

        $folder = EmailFolder::where('type', $folderType)->first();
        if (!$folder) return;

        $messageId = $imapMessage->messageId() ?? uniqid('msg_');
        
        $existing = EmailMessage::where('message_id', $messageId)->first();
        if ($existing) return;

        $from = $imapMessage->from();
        $to = $imapMessage->to();

        $message = EmailMessage::create([
            'email_folder_id' => $folder->id,
            'message_id' => $messageId,
            'subject' => $imapMessage->subject() ?? '(senza oggetto)',
            'from_name' => $from?->name() ?? '',
            'from_email' => $from?->email() ?? '',
            'to_email' => count($to) > 0 ? $to[0]->email() : '',
            'body_text' => $imapMessage->text() ?? '',
            'body_html' => $imapMessage->html() ?? '',
            'is_read' => $imapMessage->isSeen() ?? false,
            'is_starred' => $imapMessage->isFlagged() ?? false,
            'is_sent' => $folderType === 'sent',
            'received_at' => $imapMessage->date() ?? now(),
            'imap_uid' => $imapMessage->uid() ?? null,
        ]);

        $attachments = $imapMessage->attachments();
        if ($attachments && count($attachments) > 0) {
            foreach ($attachments as $attachment) {
                $filename = $attachment->filename() ?? 'attachment';
                $contents = $attachment->contents();
                $path = 'email-attachments/' . Str::uuid() . '_' . $filename;
                Storage::put($path, $contents);

                EmailAttachment::create([
                    'email_message_id' => $message->id,
                    'filename' => $filename,
                    'mime_type' => $attachment->contentType() ?? 'application/octet-stream',
                    'size' => strlen($contents),
                    'file_path' => $path,
                ]);
            }
        }
    }

    private function ensureFoldersExist()
    {
        $systemFolders = EmailFolder::getSystemFolders();
        
        foreach ($systemFolders as $folder) {
            EmailFolder::updateOrCreate(
                ['type' => $folder['type']],
                $folder
            );
        }
    }
}