<?php


namespace Helper\Mail;

use App\Models\EList;
use App\Models\Folder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

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


    /**
     * imap服务器连接实例
     * @var Imap[]
     */
    public static array $client = [];


    /**
     * 登录imap服务器
     * @param string $email
     * @param string $password
     * @param string $imap
     * @author:dc
     * @time 2023/2/5 10:46
     */
    public static function login(string $email,string $password,string $imap) {
        static::$client[$email] = new Imap();
//        $imap->debug();
        // 是否初始成功
        static::$client[$email]->login("ssl://{$imap}:993",$email,$password);
    }


    /**
     * 同步文件夹
     * @param $email
     * @return mixed
     * @author:dc
     * @time 2023/2/5 10:58
     */
    public static function syncFolder($email){

        // 读取所有文件夹,未解密
        $folders    =   static::$client[$email]->getFolder();

        DB::beginTransaction();
        foreach ($folders as $folder){

            // 处理子父文件夹
            $folder['id'] = explode('/',$folder['folder']);
            $folder['name'] = explode('/',$folder['parseFolder']);
            $pid = 0;
            foreach ($folder['id'] as $k=>$item){
                // 插入到数据库
                $pid = Folder::_insert(
                    static::$client[$email]->getId(),
                    $folder['name'][$k],
                    $item,
                    $pid
                );
            }
        }
        DB::commit();

    }


    /**
     * 同步邮件
     * @param $msgno
     * @param $email
     * @param $email_id
     * @param $folder_id
     * @param string $folder
     * @return bool
     * @author:dc
     * @time 2023/2/6 15:04
     */
    public static function syncMail($msgno,$email,$email_id,$folder_id,$folder='INBOX'):bool {
        // 选择文件夹
        try {
            $status =   Mail::$client[$email]->selectFolder($folder);
        }catch (\Throwable $e){
            Log::error($email.' 选择文件夹错误:'.$e->getMessage());
            return false;
        }
        // 是否有邮件
        if (!isset($status['EXISTS']) || !$status['EXISTS']){
            return true;
        }

        // 更新数量
        Folder::_updateNum($folder_id,$status['EXISTS'], $status['UNSEEN']??null);

        // 是否结束同步
        $end = false;

        if($msgno){
            // 固定同步邮件号
            goto SYNCEMAILLIST;
        }

        // 最后拉取的时间,如果是第一次
        $lastMsgno   =   EList::_lastMsgno($email_id, $folder_id);

        $nu = 20;
        if(!$msgno){
            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;
                }
            }
        }



        SYNCEMAILLIST:
        // 是否有id
        $dataids = EList::_getIdsByMsgno($email_id,$folder_id,$msgno);

        // 循环
        $results = Mail::$client[$email]->fetchHeader($msgno);

        if($results){
            DB::beginTransaction();
            // 批量插入
            foreach ($results as $key=>$result){
                if($key == $status['EXISTS']){
                    $end = true;
                }
                $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   =   [
                        'id'    =>  $dataids[$key]??0,
                        'msgno'   =>  $key,
                        'uid'   =>  $result['UID'],
                        'subject'   =>  $header['Subject'],
//                        'cc'    =>  $header['Cc']??'',
                        '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'],
                        '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'   =>  $use_folder_id,
                        'email_id'    =>  $use_email_id,
                        'uuid'  =>  $use_email_id.$use_folder_id.$result['UID'],
                        'is_file'  =>  MailFun::isFile($file_header[$key]['BODYSTRUCTURE']??[]) //是否附件
                    ];
                }catch (\Throwable $e){
                    Log::error('邮件解析失败:'.$e->getMessage().print_r($result,true));
                    unset($results[$key]);
                    continue;
                }

                $results[$key]  =   $data;
            }
            $ids = EmailList::_insertAll(array_values($results));
            // 提交
            DB::commit();
        }else{
            $end = true;
        }




        return [
            'ids'   =>  $ids??[],
            'folder'   =>  $status,
            'end'   =>  $end,
        ];


    }



}