<?php

namespace app\common\email;

class QqEmailImap
{
    protected $host = '{imap.qq.com:993/imap/ssl}'; // IMAP服务器地址
    protected $username; // 邮箱地址,例如:xxx@qq.com
    protected $password; // 授权码
    protected $connection;
    protected $currentFolder = 'INBOX'; // 默认是收件箱

    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    /**
     * 测试连接并登录
     */
    public function connect()
    {
        $this->connection = @imap_open($this->host . $this->currentFolder, $this->username, $this->password);
        if (!$this->connection) {
            return false;
        }
        return true;
    }

    /**
     * 切换邮箱文件夹
     */
    public function selectFolder($folder)
    {
        $this->currentFolder = $folder;
        if ($this->connection) {
            return imap_reopen($this->connection, $this->host . $folder);
        }
        return $this->connect();
    }

    public function listFolders(): array
    {
        if (!$this->connection) {
            return [];
        }

        $folders = imap_list($this->connection, $this->host, '*');

        if (!is_array($folders)) {
            return [];
        }

        $y = [];
        $j = array_map(function ($folder) use (&$y) {
            // 提取文件夹名部分
            $pos = strrpos($folder, '}');
            $encodedName = $pos !== false ? substr($folder, $pos + 1) : $folder;
            $y[] = $encodedName;
            // 尝试多种方式解码 Modified UTF-7
            $decoded = $this->decodeImapFolderName($encodedName);
            return $decoded ?: $encodedName;
        }, $folders);
        return [
            'y' => $y, // 原始
            'j' => $j, // 解码
        ];
    }

    /**
     * 获取邮件总数
     */
    public function getTotalEmails(): int
    {
        if (!$this->connection) {
            return 0;
        }
        $num = imap_num_msg($this->connection);
        return $num ?: 0;
    }

    /**
     * 分页获取邮件列表
     */
    public function getEmailsByPage(int $page = 1, int $pageSize = 10, bool $newestFirst = true): array
    {
        if (!$this->connection) {
            return [];
        }

        $total = $this->getTotalEmails();
        $emails = [];

        if ($total === 0) {
            return [];
        }

        $totalPages = ceil($total / $pageSize);
        $page = max(1, min($page, $totalPages));

        if ($newestFirst) {
            // 最新在前
            $start = max(1, $total - ($page - 1) * $pageSize);
            $end = max(1, $total - $page * $pageSize + 1);

            for ($i = $start; $i >= $end; $i--) {
                $overview = imap_fetch_overview($this->connection, $i, 0);
                if (!empty($overview)) {
                    $emails[] = $overview[0];
                }
            }
        } else {
            // 最老在前
            $start = ($page - 1) * $pageSize + 1;
            $end = min($page * $pageSize, $total);

            for ($i = $start; $i <= $end; $i++) {
                $overview = imap_fetch_overview($this->connection, $i, 0);
                if (!empty($overview)) {
                    $emails[] = $overview[0];
                }
            }
        }

        return $emails;
    }

    /**
     * 获取某封邮件的详细内容
     */
    public function getEmailContent($msgNumber)
    {
        $structure = imap_fetchstructure($this->connection, $msgNumber);
        if (!$structure) {
            return '无法获取邮件结构';
        }

        // 调试用:输出整个邮件结构
//    dump($structure);

        if (empty($structure->parts)) {
            // 单部分邮件
            $content = imap_body($this->connection, $msgNumber);
            $content = $this->decodeContent($content, $structure->encoding);
            return $content;
        } else {
            // 多部分邮件:遍历找到第一个 text/plain 或 text/html
            foreach ($structure->parts as $partNum => $partStructure) {
                $partNum++;
                if (($partStructure->type == 0 || $partStructure->type == 1) &&
                    stristr($partStructure->subtype, 'HTML') === false) {
                    // text/plain 类型
                    $content = imap_fetchbody($this->connection, $msgNumber, $partNum);
                    return $this->decodeContent($content, $partStructure->encoding);
                }
                if (($partStructure->type == 0 || $partStructure->type == 1) &&
                    stristr($partStructure->subtype, 'HTML') !== false) {
                    // 如果没找到 text/plain,尝试返回 HTML 正文
                    $content = imap_fetchbody($this->connection, $msgNumber, $partNum);
                    return $this->decodeContent($content, $partStructure->encoding);
                }
            }
        }

        return '未找到正文内容';
    }

    protected function decodeContent($content, $encoding)
    {
        switch ($encoding) {
            case 3: // base64
                $content = base64_decode($content);
                break;
            case 4: // quoted-printable
                $content = quoted_printable_decode($content);
                break;
            default:
                // 不做处理
                break;
        }

        // 自动检测并转为 UTF-8
        if (mb_detect_encoding($content, 'UTF-8', true) === false) {
            $content = mb_convert_encoding($content, 'UTF-8', 'UTF-7, UTF-8, ASCII, GBK, GB2312', 'ignore');
        }

        return $content;
    }

    /**
     * 解析邮件内容(支持多部分邮件)
     */
    protected function decodeEmailBody($structure, $msgNumber)
    {
        if (isset($structure->parts)) {
            foreach ($structure->parts as $partNum => $partStructure) {
                $partNum++;
                $data = imap_fetchbody($this->connection, $msgNumber, $partNum);

                if ($partStructure->type == 0) {
                    if ($partStructure->encoding == 3) {
                        $data = base64_decode($data);
                    } elseif ($partStructure->encoding == 4) {
                        $data = quoted_printable_decode($data);
                    }
                    return $data;
                }
            }
        }

        return '';
    }

    /**
     * 获取某封邮件的所有附件信息
     */
    public function getAttachments($msgNumber): array
    {
        $structure = imap_fetchstructure($this->connection, $msgNumber);
        if (!$structure) {
            return [];
        }

        return $this->findAttachments($structure, $msgNumber);
    }

    protected function findAttachments($structure, $msgNumber, $prefix = ''): array
    {
        $attachments = [];

        if (isset($structure->parts)) {
            foreach ($structure->parts as $index => $part) {
                $partNum = $prefix ? $prefix . '.' . ($index + 1) : ($index + 1);

                // 判断是否为附件
                if ($part->type == 5 || (isset($part->disposition) && strtolower($part->disposition) === 'attachment')) {
                    $filename = $this->getPartFilename($part);
                    $encoding = $part->encoding ?? 0;
                    $content = imap_fetchbody($this->connection, $msgNumber, $partNum);

                    switch ($encoding) {
                        case 3: // base64
                            $content = base64_decode($content);
                            break;
                        case 4: // quoted-printable
                            $content = quoted_printable_decode($content);
                            break;
                    }

                    $attachments[] = [
                        'filename' => $filename,
                        'content_type' => $this->getContentType($part),
                        'content' => $content,
                        'size' => strlen($content),
                        'part_num' => $partNum,
                    ];
                }

                // 递归处理子结构
                if (!empty($part->parts)) {
                    $attachments = array_merge($attachments, $this->findAttachments($part, $msgNumber, $partNum));
                }
            }
        }

        return $attachments;
    }

    protected function getPartFilename($part): string
    {
        $filename = '';

        if (!empty($part->dparameters)) {
            foreach ($part->dparameters as $object) {
                if (strtolower($object->attribute) === 'filename') {
                    $filename = $object->value;
                    break;
                }
            }
        }

        if (!$filename && !empty($part->parameters)) {
            foreach ($part->parameters as $object) {
                if (strtolower($object->attribute) === 'name') {
                    $filename = $object->value;
                    break;
                }
            }
        }

        // 解码 UTF-8 文件名(可能被 RFC2231 编码)
        return $this->decodeRFC2231($filename);
    }

    protected function decodeRFC2231($string)
    {
        if (preg_match("/^(.*?)''(.*?)$/i", $string, $matches)) {
            $charset = $matches[1];
            $encoded = $matches[2];
            return rawurldecode($encoded);
        }

        return $string;
    }

    protected function getContentType($part): string
    {
        $primary_mime_type = [
            "TEXT",
            "MULTIPART",
            "MESSAGE",
            "APPLICATION",
            "AUDIO",
            "IMAGE",
            "VIDEO",
            "OTHER"
        ];

        $contentType = $primary_mime_type[$part->type] ?? "OTHER";

        if (!empty($part->subtype)) {
            $contentType .= "/" . strtoupper($part->subtype);
        }

        return $contentType;
    }

    /**
     * 自定义 IMAP 文件夹名解码函数(兼容 Modified UTF-7)
     */
    public function decodeImapFolderName(string $encoded): string
    {
        // 方法 1: 使用 imap 内置解码
        $decoded = @imap_utf7_decode($encoded);
        if (mb_detect_encoding($decoded, 'UTF-8', true)) {
            return $decoded;
        }
        // 方法 2: 手动替换 Modified UTF-7 中的特殊编码
        $modified = preg_replace_callback('/&([^-~]*)-/', function ($matches) {
            $utf16be = base64_decode(str_pad(strtr($matches[1], '-_', '+/'), strlen($matches[1]) % 4, '=', STR_PAD_RIGHT));
            return mb_convert_encoding($utf16be, 'UTF-8', 'UTF-16BE');
        }, $encoded);
        // 方法 3: 如果还是没解出来,尝试从 UTF-7 转换到 UTF-8
        if (mb_detect_encoding($modified, 'UTF-8', true) === false) {
            $modified = mb_convert_encoding($modified, 'UTF-8', 'UTF-7');
        }
        return $modified;
    }

    /**
     * 邮件内容解码函数
     */
    public function decodeEmailContent($content, $charset = null)
    {
        // 如果没有指定字符集,尝试自动检测
        if (empty($charset)) {
            $charset = mb_detect_encoding($content, array('UTF-8', 'GBK', 'GB2312', 'ASCII', 'BIG5'), true);
        }

        // 如果检测不出字符集,默认使用 UTF-8
        if (!$charset) {
            $charset = 'UTF-8';
        }

        // 转换到 UTF-8
        if ($charset != 'UTF-8') {
            $content = mb_convert_encoding($content, 'UTF-8', $charset);
        }

        // 去除多余空白
        $content = trim($content);

        return $content;
    }


    /**
     * 关闭连接
     */
    public function close()
    {
        if ($this->connection) {
            imap_close($this->connection);
        }
    }
}