<?php

declare(strict_types=1);

namespace App\Services\TomTool;

use App\Services\HttpQueue as ServiceHttpQueue;
use App\Services\TomTool\Flow;
use App\Models\TelegramKey as ModelTelegramKey;
use Telegram\Bot\Api;
use Telegram\Bot\Exceptions\TelegramSDKException;
use function strip_tags;

/**
 
 更新：
    data会save清空，不再属于set
 
 new:
    TelegramVdb::make(?$botCode, ?$chatCode)
 
 快速：
    TelegramVdb::make()->save($sData)
 
 进阶：
    TelegramVdb::make()->dataArr($aData)->setFormat("html")->save();
    TelegramVdb::make()->setFormat()->data($xData)->toJson()->save();
 
 data：
    data[Arr/Str/Json]($data)
    data($aData)->toJson()
 
 action:
    save()
 
 set:
    setChatCode($code)
    setBotCode($code)
    setChatId($id) 覆盖code
    setBotToken($token) 覆盖code
    setFormat($type)
    enableDate()
 
 */

final class TelegramVdb
{
    public $sBotCode;
    public $sChatCode;
    public $sBotToken = null;
    public $iChatId = null;
    public $sMsg = '';
    public $sMsgFormat = '';
    public $sMsgFormatType = 'none';
    public $bEnableDate = false;
    private $bKeyBegin = false;
    public $sClient = "master";

    private const ALLOWED_FORMATS = ['none', 'html', 'markdown', 'markdownV2'];
    
    public static function log()
    {
        return self::make("log", "admin");
    }
    
    public static function warn()
    {
        return self::make("warn", "admin");
    }
    
    public static function fail()
    {
        return self::make("fail", "admin");
    }

    public static function notify()
    {
        return self::make("notify", "admin");
    }
    
    public static function make($sBotCode = "base", $sChatCode = "base")
    {
        $oInstance = new self();
        $oInstance->sBotCode = $sBotCode;
        $oInstance->sChatCode = $sChatCode;
        return $oInstance;
    }
    
    public function send($sMsg = '')
    {
        return $this->_ok($sMsg, true);
    }
    
    public function save($sMsg = '')
    {
        return $this->_ok($sMsg);
    }
    
    private function sendNow()
    {
        $oResult = Flow::make("send");
        $oBot = new Api($this->sBotToken);
        
        $r = $oBot->sendMessage($this->sMsgFormat);
        
        if ($r->isOk()){
            return $oResult->done();
        } else {
            return $oResult->fail("send失败");
        }
    }
    
    private function HttpQueueSave()
    {
        $aTelegramArg = [
            "bot_token" => $this->sBotToken,
            "chat_id"   => $this->iChatId,
            "msg"       => $this->sMsgFormat,
        ];

        $aReturn = ServiceHttpQueue::start("telegram")->arg($aTelegramArg)->save()->getResult();
        
        return $aReturn;
    }
    
    public function _ok($sMsg = '', $bSendNow = false)
    {
        $bTgSendEnable = $_ENV["tg_send_enable"] ?? false;
        if (!$bTgSendEnable) {
            return false;
        }
        
        $oResult = Flow::make("save");

        $this->keyBegin();

        if ($sMsg) {
            if (is_array($sMsg)) {
                $this->aData($sMsg);
            } else {
                $this->sData($sMsg);
            }
        }
        
        $this->msgFormat();
                
        if ($bSendNow) {
            $aReturn = $this->sendNow();
        } else {
            $aReturn = $this->HttpQueueSave();
        }
        
        $this->sMsg = '';

        return $aReturn;
    }
    
    public function enableDate($b = true)
    {
        $this->bEnableDate = $b;
        return $this;
    }
    
    public function data($xData)
    {
        $this->sMsg = $xData;
        return $this;
    }
    
    public function jData($sMsg = '')
    {
        $this->dataJson($sMsg);
        return $this;
    }
    
    public function aData($sMsg = [])
    {
        $this->dataArr($sMsg);
        return $this;
    }
    
    public function sData($sMsg = '')
    {
        $this->dataStr($sMsg);
        return $this;
    }
    
    public function toJson()
    {
        $this->withDateArr();
        $this->sMsg = json_encode($this->sMsg, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        return $this;
    }

    public function dataStr($sMsg = '')
    {
        $this->withDateStr();
        $this->sMsg = $sMsg;
        return $this;
    }
    
    public function dataArr($sMsg = [])
    {
        $this->withDateArr();
        $this->sMsg = json_encode($sMsg, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        return $this;
    }
    
    public function dataJson($sMsg = '')
    {
        $this->dataStr($sMsg);
        return $this;
    }
    
    private function withDateArr()
    {
        if ($this->bEnableDate) {
            $this->sMsg["date"] = date("Y-m-d H:i:s");
        }
    }
    
    private function withDateStr()
    {
        if ($this->bEnableDate) {
            $this->sMsg = '['.date("Y-m-d H:i:s").'] '.$this->sMsg;
        }
    }
    
    public function setFormat($sMsgFormatType = "none")
    {
        $this->sMsgFormatType = $sMsgFormatType;
        return $this;
    }

    public function setBotCode($sBotCode)
    {
        $this->sBotCode = $sBotCode;
        $this->bKeyBegin = false;
        return $this;
    }

    public function setChatCode($sChatCode)
    {
        $this->sChatCode = $sChatCode;
        $this->bKeyBegin = false;
        return $this;
    }

    public function setBotToken($sBotToken)
    {
        $this->sBotToken = $sBotToken;
        return $this;
    }

    public function setChatId($iChatId)
    {
        $this->iChatId = $iChatId;
        return $this;
    }

    private function keyBegin()
    {
        if (!$this->bKeyBegin) {
            if (!$this->sBotToken) {
                $this->sBotToken = $this->botTokenByCode();
            }

            if (!$this->iChatId) {
                $this->iChatId = $this->chatIdByCode();
            }

            if (!$this->sBotToken || !$this->iChatId) {
                throw new \RuntimeException("botToken或chatId没找到，botCode={$this->sBotCode}，chatCode={$this->sChatCode}");
            }

            $this->bKeyBegin = true;
        }

        return $this;
    }

    private function msgFormat()
    {
        if (!in_array($this->sMsgFormatType, self::ALLOWED_FORMATS, true)) {
            throw new \RuntimeException("不支持的格式类型: {$this->sMsgFormatType}");
        }

        $method = 'msgFormat_' . $this->sMsgFormatType;
        $this->$method();

        return $this;
    }

    private function botTokenByCode()
    {
        return ModelTelegramKey::botTokenByCode($this->sBotCode);
    }

    private function chatIdByCode()
    {
        return ModelTelegramKey::chatIdByCode($this->sChatCode);
    }

    private function msgFormat_none()
    {
        $this->sMsgFormat = [
            'chat_id' => $this->iChatId,
            'text' => $this->sMsg,
            'parse_mode' => '',
            'disable_web_page_preview' => false,
            'reply_to_message_id' => null,
            'reply_markup' => null,
        ];

        return $this;
    }

    private function msgFormat_html()
    {
        $this->sMsgFormat = [
            'chat_id' => $this->iChatId,
            'text' => strip_tags($this->sMsg, [
                'b', 'strong', 'i', 'em', 'u', 'ins', 's', 'strike', 'del', 'span', 'tg-spoiler', 'a', 'tg-emoji',
                'code', 'pre',
            ]),
            'parse_mode' => 'HTML',
            'disable_web_page_preview' => false,
            'reply_to_message_id' => null,
            'reply_markup' => null,
        ];

        return $this;
    }

    private function msgFormat_markdown()
    {
        $this->sMsgFormat = [
            'chat_id' => $this->iChatId,
            'text' => $this->sMsg,
            'parse_mode' => 'Markdown',
            'disable_web_page_preview' => false,
            'reply_to_message_id' => null,
            'reply_markup' => null,
        ];

        return $this;
    }

    private function msgFormat_markdownV2()
    {
        $this->sMsgFormat = [
            'chat_id' => $this->iChatId,
            'text' => $this->sMsg,
            'parse_mode' => 'MarkdownV2',
            'disable_web_page_preview' => false,
            'reply_to_message_id' => null,
            'reply_markup' => null,
        ];

        return $this;
    }
}
