<?php

namespace Lib\Mail;

use Lib\DbPool;
use Model\folderSql;
use Model\listsSql;

/**
 * 操作邮件
 * @author:dc
 * @time 2023/2/5 10:10
 * Class MailFun
 * @package Helper\Mail
 */
class Mail {

    /**
     * imap服务器连接实例
     * @var Imap
     */
    public Imap $client;


    /**
     * 登录imap服务器
     * @param string $email
     * @param string $password
     * @param string $imap
     * @author:dc
     * @time 2023/2/5 10:46
     */
    public function login(string $email,string $password,string $imap) {

        $this->client = new Imap();

        // 是否初始成功
        $this->client->login("ssl://{$imap}:993",$email,$password);

        return true;
    }


    /**
     * 同步文件夹
     * @param int $email_id
     * @param DbPool|null $db
     * @return mixed
     * @author:dc
     * @time 2023/2/5 10:58
     */
    public function syncFolder($email_id,$db=null){
        $db = $db ? $db : db();
        // 读取所有文件夹,未解密
        $folders    =   $this->client->getFolder();

//        $db->transaction();
        foreach ($folders as $folder){
            // 处理子父文件夹
            $folder['id'] = explode('/',$folder['folder']);
            $folder['name'] = explode('/',$folder['parseFolder']);
            $pid = 0;
            foreach ($folder['id'] as $k=>$item){
                $data = [
                    'email_id' => $email_id,
                    'folder' => $folder['name'][$k],
                    'origin_folder' => $item,
                    'pid' => $pid
                ];

                if(!$db->value(folderSql::has($data))){
                    // 插入到数据库
                    $pid = $db->insert(
                        folderSql::$table,
                        $data,
                        false
                    );
                }
            }
        }
//        $db->commit();

    }


    /**
     * 同步邮件
     * @param $email_id
     * @param $folder_id
     * @param string $folder
     * @param null|DbPool $db
     * @return bool
     * @throws \Exception
     * @author:dc
     * @time 2023/2/18 9:54
     */
    public function syncMail($email_id,$folder_id,$folder='INBOX',$db = null):bool {
//        _echo('正在同步文件夹:'.$folder);
        $db = $db ? $db : db();
        // 选择文件夹
        $status =   $this->client->selectFolder($folder);

        // 是否有邮件
        if (!isset($status['EXISTS']) || !$status['EXISTS']){
            return true;
        }

        // 更新数量
        $db->update(
            folderSql::$table,
            ['exsts'=>$status['EXISTS'],'unseen'=>$status['UNSEEN']??0],
            dbWhere(['id'=>$folder_id]),
            false
        );


        // 最后拉取的msgno
        $lastMsgno   =   $db->value(listsSql::lastMsgno($email_id,$folder_id));

        $nu = 20;

        if(!$lastMsgno){
            $msgno = range(1,$nu);
        }else{
            $msgno = range($lastMsgno,$lastMsgno+$nu);

            if($lastMsgno > $status['EXISTS']){
                $msgno = range($status['EXISTS'] > $nu ? $status['EXISTS'] - $nu : 1,$status['EXISTS']);
            }
            // 一样就不拉新的
            if($lastMsgno == $status['EXISTS']){
                return true;
            }
        }


        // 循环
        $results = $this->client->fetchHeader($msgno);
        if($results){
            // 批量插入
            foreach ($results as $key=>$result){
                $header = $result['HEADER.FIELDS'];

                foreach ($result['FLAGS'] as $k=>$FLAG){
                    $result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
                }
                try {

                    $file_header = $result['BODYSTRUCTURE'];

                    // 没有收件人
                    if(!empty($header['To'])){
                        $header['To'] = MailFun::toOrFrom($header['To']);
                    }else{
                        $header['To'] = [];
                    }

                    $header['From'] = MailFun::toOrFrom($header['From']);

                    $data   =   [
                        'msgno'   =>  $key,
                        'uid'   =>  $result['UID'],
                        'subject'   =>  $header['Subject'],
                        'cc'    =>  $header['Cc']??'',
                        'bcc'    =>  $header['Bcc']??'',
                        'from'   =>  $header['From'][0]['email']??'',
                        'from_name'   =>  $header['From'][0]['name']??'',
                        'to'   =>  $header['To']?implode(',',array_column($header['To'],'email')):'',
                        'to_name'   =>  json_encode($header['To']),
                        'date'   =>  isset($header['Date'])&&$header['Date'] ? strtotime(is_array($header['Date']) ? $header['Date'][0] : $header['Date']) : strtotime($result['INTERNALDATE']),
                        'message_id'   =>  $header['Message-ID']??'',
                        'udate'   =>  strtotime($result['INTERNALDATE']),
                        'size'   =>  $result['RFC822.SIZE']??0,
                        'recent'   =>  in_array('recent',$result['FLAGS']),
                        'seen'   =>  in_array('seen',$result['FLAGS']),
                        'draft'   =>  in_array('draft',$result['FLAGS']),
                        'flagged'   =>  in_array('flagged',$result['FLAGS']),
                        'answered'   =>  in_array('answered',$result['FLAGS']),
                        'folder_id'   =>  $folder_id,
                        'email_id'    =>  $email_id,
                        'uuid'  =>  md5($email_id.$folder_id.$result['UID']),
                        'is_file'  =>  MailFun::isFile($file_header[$key]['BODYSTRUCTURE']??[]) //是否附件
                    ];
                }catch (\Throwable $e){
                    logs(
                        '邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),
                        LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'
                    );
                    unset($results[$key]);
                    continue;
                }

                $results[$key]  =   $data;
            }

            // 保存数据,这里其实不用再次写循环的。我想写一个
            $uuids = $db->all(listsSql::hasUuid(array_column($results,'uuid')));
            $uuids = $uuids ? array_column($uuids,null,'uuid') : [];

//            $db->transaction();
            foreach ($results as $insert){
                if(empty($uuids[$insert['uuid']])){
                    // 新增
                    $db->insert(listsSql::$table,$insert);
                }else{
                    // 修改
                    $db->update(
                        listsSql::$table,
                        $insert,
                        dbWhere(['id'=>$uuids[$insert['uuid']]['id']])
                    );
                }
            }
//            $db->commit();

            // 更新数量
            $db->update(
                folderSql::$table,
                ['last_sync_time' => time()],
                dbWhere(['id'=>$folder_id]),
                false
            );
            // 结束操作了

            // 再次调用
            $this->syncMail($email_id,$folder_id,$folder,$db);
        }

        return true;

    }


    /**
     * 同步 邮件 内容 body
     * @param $id
     * @param $msgno
     * @param $email_id
     * @param $folder_name
     * @param $email
     * @return bool
     * @throws \Exception
     * @author:dc
     * @time 2023/2/9 10:29
     */
    public static function syncBody($id,$msgno, $email_id,$folder_name,$email):bool {

        // 选择文件夹
        static::$client[$email]->selectFolder($folder_name);

        $body = static::$client[$email]->fetchBody([$msgno],storage_path('email/'.$email_id));

        if(!empty($body[$msgno]['RFC822.TEXT'])){
            \App\Models\Body::_insert($id,$body[$msgno]['RFC822.TEXT']);
        }

        return true;

    }



}