<?php

namespace App\Services\IM;

use Illuminate\Database\Eloquent\Collection;
use JsonSerializable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;

class CustomElem implements Arrayable, Jsonable, JsonSerializable
{
    /** @var string 消息类型 */
    private $msgType;
    /** @var array 消息体 */
    private $content;
    private $desc;
    private $ext;
    private $sound;

    /**
     * CustomElem constructor.
     * @param string $msgType
     * @param array $content
     * @param string $desc
     * @param string $ext
     * @param string $sound
     */
    public function __construct(string $msgType, array $content = array(), string $desc = "", string $ext = "", string $sound = "")
    {
        Collection::make();
        $this->msgType = $msgType;
        $this->content = $content;
        $this->desc = $desc;
        $this->ext = $ext;
        $this->sound = $sound;
    }

    /**
     * @param string $msgType
     * @param array $content
     * @param string $desc
     * @param string $ext
     * @param string $sound
     * @return static
     */
    public static function make(string $msgType, array $content = array(), string $desc = "", string $ext = "", string $sound = "")
    {
        return new static($msgType, $content, $desc, $ext, $sound);
    }

    private function getTIMMsgElement(): array
    {
        return array(
            "MsgType" => "TIMCustomElem",
            "MsgContent" => [
                'Data' => json_encode([
                    'MsgType' => $this->msgType,
                    'Content' => $this->content ?? null
                ]),
                'Desc' => $this->desc,
                'Ext' => $this->ext,
                'Sound' => $this->sound
            ]
        );
    }

    public function jsonSerialize()
    {
        return array_map(function ($value) {
            if ($value instanceof JsonSerializable) {
                return $value->jsonSerialize();
            } elseif ($value instanceof Jsonable) {
                return json_decode($value->toJson(), true);
            } elseif ($value instanceof Arrayable) {
                return $value->toArray();
            }
            return $value;
        }, $this->getTIMMsgElement());
    }

    public function toJson($options = 0)
    {
        return json_encode($this->jsonSerialize(), $options);
    }

    public function toArray(): array
    {
        return array_map(function ($value) {
            return $value instanceof Arrayable ? $value->toArray() : $value;
        }, $this->getTIMMsgElement());
    }
}
