<?php

namespace App\Models;

use DateTimeImmutable;
use App\ColorPicker;
use Carbon\Carbon;
use DateTime;
use Ddeboer\Imap\Search\Email\Cc;
use Ddeboer\Imap\Search\Email\To;
use Ddeboer\Imap\SearchExpression;
use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

class Message extends Model
{
    use ColorPicker, HasFactory;

    protected $fillable = [
        'subject',
        'from',
        'to',
        'body',
        'attachments',
        'is_seen',
    ];

    public static function store(Request $request): void
    {
        $message = new Message;
        $message->subject = $request->subject;
        $message->from = $request->from;
        $message->to = $request->to;
        $message->body = $request->has('html') ? $request->html : $request->text;
        $message->save();
        if ($request->has('content-ids')) {
            $message->attachments = $request->get('attachment-info');
            $message->save();
            $directory = './attachments/'.$message->id;
            if (!is_dir($directory)) {
                mkdir($directory, 0777, true);
            }
            $attachment_ids = json_decode((string) $request->get('attachment-info'));
            foreach ($attachment_ids as $attachment_id => $attachment_info) {
                $allowed = explode(',', 'csv,doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt');
                $file = explode('.', (string) $attachment_info->filename);
                if (in_array($file[count($file) - 1], $allowed)) {
                    Storage::disk('tmp')->putFileAs($directory, $request->file($attachment_id), $attachment_info->filename);
                }
            }
        }
    }

    public static function getMessages(string $email): array
    {
        $limit = json_decode((string) config('app.settings.configuration_settings'))->fetch_messages_limit ?? 15;
        $messages = Message::query()->where('to', $email)->orWhere('to', 'like', '%<'.$email.'>%')->limit($limit)->get();
        $response = [
            'data' => [],
            'notifications' => [],
        ];
        foreach ($messages as $message) {
            $content = str_replace('<a', '<a target="blank"', $message->body);
            if (json_decode((string) config('app.settings.configuration_settings'))->enable_masking_external_link) {
                $content = str_replace('href="', 'href="https://href.li/?', $content);
            }
            $obj = [];
            $obj['subject'] = $message->subject;
            $sender = explode('<', (string) $message->from);
            $obj['sender_name'] = $sender[0];
            $obj['sender_email'] = isset($sender[1]) ? str_replace('>', '', $sender[1]) : $obj['sender_name'];
            $obj['timestamp'] = $message->created_at;
            $obj['date'] = $message->created_at->format(json_decode((string) config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A');
            $obj['datediff'] = $message->created_at->diffForHumans();
            $obj['id'] = $message->id;
            $obj['content'] = $content;
            $obj['attachments'] = [];
            $domain = explode('@', $obj['sender_email'])[1];
            $blocked = in_array($domain, json_decode((string) config('app.settings.configuration_settings'))->blocked_domains);
            if ($blocked) {
                $obj['subject'] = __('Blocked');
                $obj['content'] = __('Emails from').' '.$domain.' '.__('are blocked by Admin');
            }
            if ($message->attachments && ! $blocked) {
                $attachments = json_decode((string) $message->attachments);
                foreach ($attachments as $id => $attachment) {
                    $url = config('app.settings.app_base_url').'/tmp/attachments/'.$message->id.'/'.$attachment->filename;
                    if (str_contains($obj['content'], (string) $id)) {
                        $obj['content'] = str_replace('cid:'.$id, $url, $obj['content']);
                    } elseif (Storage::disk('tmp')->exists('attachments/'.$message->id.'/'.$attachment->filename)) {
                        $obj['attachments'][] = [
                            'file' => $attachment->filename,
                            'url' => $url,
                        ];
                    }
                }
            }
            $response['data'][] = $obj;
            if (! $message->is_seen) {
                $response['notifications'][] = [
                    'subject' => $obj['subject'],
                    'sender_name' => $obj['sender_name'],
                    'sender_email' => $obj['sender_email'],
                ];
                if (config('app.zemail_log')) {
                    file_put_contents(storage_path('logs/zemail.csv'), request()->ip().','.date('Y-m-d h:i:s a').','.$obj['sender_email'].','.$email.PHP_EOL, FILE_APPEND);
                }
                $message->is_seen = true;
                $message->save();
            }
        }

        return $response;
    }

    public static function fetchMessages(string $email, $type = 'to', $deleted = []): array
    {
        $allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt');
        $connection = ZEmail::connectMailBox();

        $mailbox = $connection->getMailbox('INBOX');
        $search = new SearchExpression;
        if ($type == 'cc') {
            $search->addCondition(new Cc($email));
        } else {
            $search->addCondition(new To($email));
        }
        $messages = $mailbox->getMessages($search, \SORTDATE, true);
        $limit = json_decode((string) config('app.settings.configuration_settings'))->fetch_messages_limit ?? 15;
        $count = 1;
        $response = [
            'data' => [],
            'notifications' => [],
        ];

        foreach ($messages as $message) {
            if (in_array($message->getNumber(), $deleted)) {
                $message->delete();

                continue;
            }
            $blocked = false;
            $sender = $message->getFrom();
            $date = $message->getDate();
            if (!$date instanceof DateTimeImmutable) {
                $date = new DateTime;
                if ($message->getHeaders()->get('udate')) {
                    $date->setTimestamp($message->getHeaders()->get('udate'));
                }
            }
            $datediff = new Carbon($date);
            $content = '';
            $contentText = '';
            $html = $message->getBodyHtml();
            $text = $message->getBodyText();
            if ($text) {
                $contentText = str_replace('<a', '<a target="blank"', str_replace(["\r\n", "\n"], '', $text));
            }
            if ($html) {
                $content = str_replace('<a', '<a target="blank"', $html);
            } else {
                $content = str_replace('<a', '<a target="blank"', str_replace(["\r\n", "\n"], '<br/>', $text));
            }
            if (json_decode((string) config('app.settings.configuration_settings'))->enable_masking_external_link) {
                $content = str_replace('href="', 'href="http://href.li/?', $content);
            }
            $obj = [];
            $obj['subject'] = $message->getSubject();
            $obj['sender_name'] = $sender->getName();
            $obj['sender_email'] = $sender->getAddress();
            $obj['timestamp'] = $message->getDate();
            $obj['date'] = $date->format(json_decode((string) config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A');
            $obj['datediff'] = $datediff->diffForHumans();
            $obj['id'] = $message->getNumber();
            $obj['content'] = $content;
            $obj['contentText'] = $contentText;
            $obj['attachments'] = [];
            $obj['is_seen'] = true;
            $obj['sender_photo'] = self::chooseColor(strtoupper(substr($sender->getName() ?: (string) $sender->getAddress(), 0, 1)));

            // Checking if Sender is Blocked
            $domain = explode('@', (string) $obj['sender_email'])[1];
            $blocked = in_array($domain, json_decode((string) config('app.settings.configuration_settings'))->blocked_domains);
            if ($blocked) {
                $obj['subject'] = __('Blocked');
                $obj['content'] = __('Emails from').' '.$domain.' '.__('are blocked by Admin');
                $obj['contentText'] = __('Emails from').' '.$domain.' '.__('are blocked by Admin');
            }
            if ($message->hasAttachments() && ! $blocked) {
                $attachments = $message->getAttachments();
                $directory = './tmp/attachments/'.$obj['id'].'/';
                if (!is_dir($directory)) {
                    mkdir($directory, 0777, true);
                }
                foreach ($attachments as $attachment) {
                    $filenameArray = explode('.', (string) $attachment->getFilename());
                    $extension = $filenameArray[count($filenameArray) - 1];
                    if (in_array($extension, $allowed)) {
                        if (! file_exists($directory.$attachment->getFilename())) {
                            try {
                                file_put_contents(
                                    $directory.$attachment->getFilename(),
                                    $attachment->getDecodedContent()
                                );
                            } catch (Exception $e) {
                                Log::error($e->getMessage());
                            }
                        }
                        if ($attachment->getFilename() !== 'undefined') {
                            $url = config('app.settings.app_base_url').str_replace('./', '/', $directory.$attachment->getFilename());
                            $structure = $attachment->getStructure();
                            if (isset($structure->id) && str_contains((string) $obj['content'], trim($structure->id, '<>'))) {
                                $obj['content'] = str_replace('cid:'.trim($structure->id, '<>'), $url, $obj['content']);
                            }
                            $obj['attachments'][] = [
                                'file' => $attachment->getFilename(),
                                'url' => $url,
                            ];
                        }
                    }
                }
            }
            $response['data'][] = $obj;
            if (! $message->isSeen()) {
                $response['notifications'][] = [
                    'subject' => $obj['subject'],
                    'sender_name' => $obj['sender_name'],
                    'sender_email' => $obj['sender_email'],
                ];
                if (config('app.zemail_log')) {
                    file_put_contents(storage_path('logs/zemail.csv'), request()->ip().','.date('Y-m-d h:i:s a').','.$obj['sender_email'].','.$email.PHP_EOL, FILE_APPEND);
                }
            }
            $message->markAsSeen();
            if (++$count > $limit) {
                break;
            }
        }

        $response['data'] = array_reverse($response['data']);
        $connection->expunge();

        return $response;
    }
}
