<?php

namespace Lib\Imap\Parse;

use Lib\Imap\DataArray;

/**
 * 邮件内容
 * @author:dc
 * @time 2024/9/20 14:57
 * Class Body
 * @package Lib\Imap\Parse
 */
class Body {

    /**
     * 原始数据
     * @var string
     */
    protected string $raw = '';

    /**
     * 消息结构,解析后的邮件体 header
     * @var MessageItem
     */
    protected MessageItem $msg;


    /**
     * 解析后的body数据
     * @var DataArray[]
     */
    private array $items = [];

    /**
     * Body constructor.
     * @param string $result
     * @param MessageItem $msg
     */
    public function __construct(string $result, MessageItem $msg)
    {
        $this->raw = $result;

        $this->msg = $msg;

        $this->parse();
    }



    /**
     * 解析
     * @author:dc
     * @time 2024/9/14 17:35
     */
    protected function parse(){
        // 是否是多段
        $boundary = $this->msg->header->getBoundary();
        if($boundary){
            // 切割成块 boundary 的结束符号 前后都会多2个--
            $items = explode($boundary,
                str_replace('--'.$boundary.'--',$boundary,$this->raw)
            );
            // 第一个块和最后一块 是没用的块
            array_shift($items);array_pop($items);
            foreach ($items as $item){
                $this->items[] = $this->parseItem($item);
            }
        }
        // 不是多块级
        if(stripos($this->msg->header->get('content-type'),'text/')===0){
            $this->parseRawHtml();
        }


    }

    /**
     * 解析 不是多块级的邮件体 直接就是html或者text的
     * @author:dc
     * @time 2024/9/21 11:37
     */
    private function parseRawHtml() {

        $data = $this->parseMimeHeader('Content-Type: '.$this->msg->header->get('content-type'));

        // 设置编码规则
        if($this->msg->header->get('Content-Transfer-Encoding')){
            $data->set('Content-Transfer-Encoding',$this->msg->header->get('Content-Transfer-Encoding'));
        }

        // 是否是item fetch
        if(preg_match('/^\* \d+ FETCH \(/',$this->raw)){
            $body = mb_substr(trim($this->raw),strpos($this->raw,'(')+1,-1);
            // 打散成数组
            $body = explode("\r\n",trim($body));
            /***************** start 第一行处理 **************/
            // 第一行 UID 1568602721 RFC822.TEXT {589}
            $first = explode(' ',$body[0]);
            while (1){ if(str_starts_with(array_shift($first), 'RFC822.')) break; }
            $first = array_values($first);
            $first[0] = preg_replace("/^\{\d+\}/",'',$first[0]);
            // 第一行的结果就是 踢出 UID 1568602721 RFC822.TEXT {589}
            $body[0] = implode("\r\n",$first);
            /***************** end 第一行处理 **************/
//            -----------------------------------------------------------
            /***************** start 最后一行处理 **************/
            // 最后一行可能是 UID 1568602721 微软的就是
            $end  = trim(end($body));
            $end = preg_replace("/(UID \d+)|(FLAGS \([\\a-z* ]*\))/",'',$end);
            if(!trim($end)){ array_pop($body); }
            /***************** end 最后一行处理 **************/

            // 再次组装成字符串
            $data->body = trim(implode("\r\n",$body));

            $this->items[] = $this->bodyDeCode($data);

        }

    }


    /**
     * 解析每个 块
     * @param string $body 块字符串
     * @return DataArray
     * @author:dc
     * @time 2024/9/21 9:51
     */
    protected function parseItem(string $body):DataArray {
        list($mime_header,$text) = explode("\r\n\r\n",$body,2);

        // 解析头部
        $data = $this->parseMimeHeader($mime_header);

        $data->body = $text;

        return $this->bodyDeCode($data);

    }

    /**
     * @param DataArray $data
     * @return DataArray
     * @author:dc
     * @time 2024/9/21 11:39
     */
    private function bodyDeCode(DataArray $data):DataArray {
        // 处理body体 的编码
        switch ($data->get('Content-Transfer-Encoding')){
            case 'quoted-printable':{
                $data->body = quoted_printable_decode($data->body);break;
            }
            case 'base64':{
                $data->body = base64_decode($data->body);break;
            }
        }
        return $data;
    }


    /**
     * 解析邮件体里面的每个块 头部
     * @param string $header
     * @return DataArray
     * @author:dc
     * @time 2024/9/21 9:18
     */
    protected function parseMimeHeader(string $header):DataArray {
        // 处理 描述信息,
        $header = explode("\r\n",trim($header));
        $data = new DataArray();
        $name = '';
        foreach ($header as $head){
            // 判断是否是上一行的
            if(str_starts_with($head,' ') || str_starts_with($head,"\t")){
                $data->set($name,' '.$head,true);
            }else{
                list($name,$value) = explode(":",$head,2);
                $data->set($name,trim($value));
            }
        }

        // 处理编码
        if($data->get('Content-Type')){
            // 切割成 每个小块 Content-Type: text/html;charset=utf-8
            $contentType = explode(' ',trim(str_replace(';',' ',$data->get('Content-Type'))));
            foreach ($contentType as $ct){
                $ct = trim($ct);
                // 这个才是真的类型
                if(str_contains($ct,'/')){
                    $data->set('Content-Type',$ct);
                }elseif (str_contains($ct,'=')){
                    // 这里包含了其他
                    list($name,$val) = explode('=',$ct);
                    $data->set($name,trim(str_replace('"','',$val)));
                }
            }
        }

        // 默认编码
        if(!$data->Charset) $data->Charset = 'utf-8';

        return $data;
    }


    /**
     * 读取纯文本的内容
     * @author:dc
     * @time 2024/9/21 9:55
     */
    public function getText():string {
        foreach ($this->items as $item){
            if($item->eq('content-type','text/plain')){
                return $item->body;
            }
        }

        // 没找到 text
        return strip_tags($this->getHtml());

    }

    /**
     * 读取 html文本
     * @return string
     * @author:dc
     * @time 2024/9/21 10:02
     */
    public function getHtml():string {
        foreach ($this->items as $item){
            if($item->eq('content-type','text/html')){
                return $item->body ? : '';
            }
        }
        return '';
    }

    /**
     * 有些邮件里面的图片是通过附件的形式发来的
     * <img src="cid:xxxx" /> 这种就是附件图片,需要替换的
     * @return array
     * @author:dc
     * @time 2024/9/21 10:53
     */
    public function getHtmlAndImg():array {
        $html = $this->getHtml();

    }

    /**
     * 读取附件
     * @return DataArray[]
     * @author:dc
     * @time 2024/9/21 10:05
     */
    public function getAttachment():array {

    }



}