package com.gh.gamecenter.feature.entity

import android.os.Parcelable
import android.text.TextUtils
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.entity.Display
import com.gh.gamecenter.common.entity.IconFloat
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.core.provider.IAppProvider
import com.gh.gamecenter.feature.HaloApp
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.provider.IRegionSettingHelperProvider
import com.gh.gamecenter.feature.provider.IVHelperProvider
import com.gh.gamecenter.feature.utils.ContentBlockedHelper
import com.google.gson.annotations.SerializedName
import com.lightgame.download.DownloadEntity
import com.therouter.TheRouter
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.Map

/**
 * 关联的后端数据库结构说明 <a href="https://wiki.shanqu.cc/pages/viewpage.action?spaceKey=ghzs&title=static_game_digest">...</a>
 */
@Parcelize
data class GameEntity(
    @SerializedName("_id")
    private var _id: String = "",
    @SerializedName("icon")
    private var mIcon: String? = null,
    @SerializedName("ori_icon")
    private var mRawIcon: String? = null,
    @SerializedName("icon_subscript")
    var mIconSubscript: String? = null,
    @SerializedName("name")
    private var mName: String? = null,
    @SerializedName("subtitle")
    private var mSubtitle: String = "", // 副标题
    @SerializedName("subtitle_style")
    private var mSubtitleStyle: TagStyleEntity? = null,
    @SerializedName("advance_download") // 预下载 https://git.shanqu.cc/pm/halo/halo-app-issues/-/issues/1839
    private var mAdvanceDownload: Boolean = false,
    @SerializedName("brief")
    private var mBrief: String? = null,

    @SerializedName("appointment")
    private var mReservable: Boolean = false, // 此游戏是否处于可预约状态
    @SerializedName("appointment_button")
    var reserveStatus: String = "", // 预约状态供用户预约列表使用，值存在的话，有两种值 -> appointment(已预约), download(已上线)

    private var apk: ArrayList<ApkEntity>? = null,
    @SerializedName("apk_search")
    private var mApkSearch: ArrayList<ApkEntity>? = null,
    @SerializedName("apk_index")
    private var mApkIndex: ArrayList<ApkEntity>? = null,

    // 多版本相关的东西 https://git.shanqu.cc/pm/halo/halo-app-issues/-/issues/819#note_43755
    var collection: ArrayList<GameCollectionEntity> = ArrayList(),
    // 开测表相关的东西
    @SerializedName("open_test")
    var test: TestEntity? = null,

    @SerializedName("d_button_add_word")
    private var mDownloadAddWord: String? = null,

    var image: String? = null,
    var type: String? = null,
    var isPluggable: Boolean = false, // 是否是在插件化区域中

    // 通用跳转相关的东西
    var link: String? = null,
    var text: String? = "",
    @SerializedName("link_community", alternate = ["community"])
    var community: CommunityEntity? = CommunityEntity(),
    var display: Display? = null,

    // 下载弹窗相关的东西
    @SerializedName("apk_link")
    var apkLink: ArrayList<ApkLink>? = null,

    @SerializedName("concern_article_exists")
    var isNewsExists: Boolean = true,

    @SerializedName("download_off_text")
    private var mDownloadOffText: String? = null,

    @SerializedName("download_off_status")
    private var mDownloadOffStatus: String? = null, // "off/dialog/toast/third_party", 只关闭、关闭且弹窗、关闭且toast、跳转第三方

    @SerializedName("download_off_dialog")
    private var mDownloadOffDialog: Dialog? = null,

    @SerializedName("server_type")
    var serverType: String? = null,

    @SerializedName("server_label")
    var serverLabel: ColorEntity? = null,

    @SerializedName("server")
    var serverEntity: ServerCalendarEntity? = null,

    @SerializedName("remaining_server")
    var serverRemaining: List<GameEntity>? = null,

    // 下载状态
    @SerializedName("download_status")
    var downloadStatus: String? = "",

    // 额外的下载方式，用于双下载类型时使用。可能的值为 "off/on/smooth/smooth_32"，分别为关闭/畅玩64位/畅玩32位
    @SerializedName("download_extra_status")
    private var mDownloadStatusExtra: String = "off",
    // 优先的下载方式，用于双下载类型时使用。可能的值为 "smooth/local"，分别为 畅玩下载/普通下载
    @SerializedName("download_default")
    private var mDefaultDownloadType: String = "",

    var kaifuTimeHint: Long? = null,

    var subjectData: GameSubjectData? = null,

    // 所有标签(插件标签和游戏标签)
    @SerializedName(value = "new_tag_style")
    private var mTagStyle: ArrayList<TagStyleEntity> = ArrayList(),
    var des: String? = null,

    // 用于开服表标记是否为置顶项目
    @SerializedName("is_fixed_top")
    var fixedTop: Boolean? = false,
    var fixedTopHint: Boolean? = false,

    @SerializedName("download_notice")
    val downloadAd: LinkEntity? = null,

    // 关联应用，供首页替换游戏确定该游戏是否应该被替换使用
    @SerializedName("relation_game_ids")
    var relatedGameIds: ArrayList<String>? = arrayListOf(),

    @SerializedName("download_dialog")
    var downloadDialog: ArrayList<Dialog>? = arrayListOf(),

    @SerializedName("is_related")
    var isRelated: Boolean = false,

    @SerializedName("rating_open")
    var isRatingOpen: Boolean = false,

    @SerializedName("zone_open")
    var isZoneOpen: Boolean = false,

    @SerializedName("bbs_open")
    var isBbsOpen: Boolean = false,

    @SerializedName("show_comment")
    var showComment: Boolean = false, // 游戏评论是否打开

    // 分类，取值有 online (网络游戏) , local (单机游戏)， welfare (福利游戏)，simulator（模拟器游戏）
    @SerializedName("category")
    private var mCategory: String? = "",
    // 7天下载量
    var download: Int = 0,
    // subject -> imageSlide
    val games: List<GameEntity>? = null,

    //首页设置
    @SerializedName("home_setting")
    val homeSetting: HomeSetting = HomeSetting(),
    @SerializedName("index_plugin")
    var indexPlugin: String = "open",

    var info: GameInfo? = null,

    @SerializedName("permission_dialog_status")
    var permissionDialogStatus: String? = "", // 权限弹窗，off(关闭)、on(开启)，默认：off

    // 镜像数据，细节见 [RegionSettingHelper]
    @SerializedName("mirror_status")
    var mirrorStatus: String? = "",
    @SerializedName("mirror_data")
    private var mMirrorData: GameEntity? = null,
    // 镜像数据 2
    @SerializedName("mirror_status2")
    var mirrorStatus2: String? = "",
    @SerializedName("mirror_data2")
    private var mMirrorData2: GameEntity? = null,

    // 游戏评分
    @SerializedName("new_star")
    val star: Float = -1F,
    // 游戏评分数量
    @SerializedName("comment_count")
    var commentCount: Int = 0,
    // 是否支持不安装直接评论
    @SerializedName("direct_comment")
    var directComment: Boolean = false,
    @SerializedName("h5_link")
    private var mH5Link: LinkEntity? = null,
    @SerializedName("played_time")
    var playedTime: Long = 0,
    @SerializedName("played_game_id")
    val playedGameId: String = "",
    @SerializedName("mutex_package")
    val mutexPackage: List<String>? = null,
    @SerializedName("version_number")
    private val mVersionNumber: String = "",// 无版号无内购无弹窗、无版号无内购有弹窗、无版号有内购、有版号
    @SerializedName("plugin_link")
    val pluginLink: List<PluginLink> = arrayListOf(),
    @SerializedName("p_button_add_word")
    var pluginDesc: String = "", //插件功能描述
    var pluggableCollection: GameCollectionEntity? = null, //插件化包所在的合集
    @SerializedName("assign_remark")
    private val _assignRemark: AssignRemark? = null, // 特殊样式显示的配置
    @SerializedName("zone_setting")
    var zone: ZoneEntity = ZoneEntity(),
    @SerializedName("comment_description")
    var commentDescription: String = "",
    @SerializedName("ignore_comment")
    var ignoreComment: Boolean = false,
    @SerializedName("overseas_address_dialog")
    var overseasAddressDialog: AddressDialog? = null,
    @SerializedName("land_page_address")
    var landPageAddressDialog: AddressDialog? = null,
    var simulator: SimulatorEntity? = null,
    @SerializedName("simulator_type")
    var simulatorType: String = "",
    @SerializedName("is_recently_played")
    var isRecentlyPlayed: Boolean = false,
    var active: Boolean = true,
    @SerializedName("package_dialog")
    val packageDialog: PackageDialogEntity? = null,
    // 视频信息，微信游戏返回video_info字段，其他游戏返回top_video字段
    @SerializedName("top_video", alternate = ["video_info"])
    val topVideo: SimpleVideoEntity? = null,
    @SerializedName("column_recommend")
    val columnRecommend: LinkEntity? = null,

    @SerializedName("simulator_config_url")
    val simulatorGameConfig: String? = "",

    @SerializedName("content_tag")
    val contentTag: ContentTag? = null,

    @SerializedName("update_time")
    val updateTime: Long = 0L,

    @SerializedName("bbs_id")
    var bbsId: String = "",

    //游戏单推荐分数
    @SerializedName("recommend_star")
    var recommendStar: Int = 5,
    //游戏单推荐理由
    @SerializedName("recommend_text")
    private var _recommendText: String = "",

    // 专题封面图
    @SerializedName("column_image")
    var columnImage: String = "",

    @SerializedName("google_status")
    var gAppsSwitch: String? = "", // 是否需要谷歌框架，目前只用在畅玩游戏里使用

    @SerializedName("column_rank")
    var columnRank: ColumnRank? = null,//榜单详情
    @SerializedName("ad_icon_active")
    var adIconActive: Boolean = false,// 游戏广告 true显示，false隐藏。只有当type=ad时才会返回该字段
    @SerializedName("recommend_tag")
    var recommendTag: String = "",
    @SerializedName("event_type")
    var eventType: String = "",// 事件类型（test：测试、first：首发、update：更新、appointment：预约）
    var time: TimeEntity? = null,

    @SerializedName("icon_float")
    var mIconFloat: IconFloat? = null,//图标浮层

    // 镜像字段
    @SerializedName("content_tag_status")
    val contentTagStatus: String = "off",//on（生效）/off（不生效）

    // 镜像字段
    @SerializedName("mirror_server")
    val mirrorServer: GameDetailServer? = null,

    // 消息ID，用于首页求加速上架提醒弹窗
    @SerializedName("message_private_id")
    var messageId: String = "",

    // 小游戏用户ID，目前仅用于微信小游戏CPM，对应着小游戏的appid字段
    @SerializedName("wxappid")
    var miniGameUid: String = "",
    // 小游戏ID，仅用于小游戏
    // 如果是微信小游戏，则对应着小游戏的user_name字段
    // 如果是QQ小游戏，则对应着小游戏的game_id字段
    @SerializedName("appid")
    var miniGameAppId: String = "",
    // 小游戏状态(1：下架 2：秒玩)，仅用于小游戏
    @SerializedName("app_status")
    var miniGameAppStatus: Int = 0,
    // 小游戏类别（qq/wechat），仅用于小游戏
    @SerializedName("game_type")
    var miniGameCategory: String = "",
    // 小游戏链接URL，仅用于小游戏
    @SerializedName("appidLink")
    var miniGameAppLink: String = "",
    // 小游戏跳转path，目前仅用于微信小游戏CPM
    var miniGameAppPath: String = "",
    // 小游戏跳转extData，目前仅用于微信小游戏CPM
    var miniGameExtData: String = "",
    // 小游戏广告推荐ID，目前仅用于微信小游戏CPM
    var miniGameRecommendId: String = "",
    // 使用人数，仅用于微信小游戏
    var usage: Int = 0,
    // 游戏封面图，仅用于微信小游戏
    var banner: String = "",
    // 收益来源(CPM & DSP)，用于 CPM 和 DSP 的游戏
    var profit: String = "",
    // 宣传图，仅用于微信小游戏
    @SerializedName("publicity_img")
    var publicityImg: List<String>? = null,
    // 小游戏在搜索结果的位置，仅用于微信小游戏CPM搜索结果列表
    var location: Int = -1,
    @SerializedName("first_setting")
    var firstSetting: FirstSetting? = null,
    @SerializedName("bubble_text")
    var bubbleText: String = "",
    @SerializedName("show_subtitle")    // 是否展示副标题只有展开大图样式的游戏专题下的 GameEntity 才会返回
    val showSubtitle: Boolean = false,
    @SerializedName("show_icon_subscript")
    val showIconSubscript: Boolean = false, //是否展示角标,只有展开大图样式的游戏专题下的 GameEntity 才会返回
    @SerializedName("welfare_info")
    val welfareInfo: WelfareInfo? = null, // 福利信息，只有 单游戏卡片 样式的游戏专题下的 GameEntity 才会返回
    @SerializedName("abbreviation")
    private val _abbreviation: String? = null,   // 略缩名 只有单游戏卡片 样式的游戏专题下的 GameEntity 才会返回
    @SerializedName("appointment_count")
    private val _appointmentCount: Int? = null,
    @SerializedName("selling_points")
    var sellingPoints: SellingPoints? = null,

    // 资讯数据
    @SerializedName("article_data")
    var articleData: CommunityTopEntity? = null,
    @SerializedName("wifi_auto_download")
    private val _wifiAutoDownload: Boolean? = null, // 只有预约上线弹窗/我的预约接口接口会返回这个字段
    @SerializedName("accelerator_status")
    private var _acceleratorStatus: Boolean? = null,
    @SerializedName("service_area")
    private var _serviceArea: List<AcctGameInfo.ZoneInfo>? = null,
    @SerializedName("explain_text")
    private val _explainText: String? = null,

    // 本地字段
    // 用来标记在专题中的序号，仅用于曝光记录
    var sequence: Int? = -1,
    // 用来标记在外部页面中的序号，仅用于曝光记录，具体细节可见 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087
    var outerSequence: Int? = -1,
    // 用来标记平台名称，仅用于曝光记录
    var platform: String? = null,

    // 用来标记下载的类型，仅用于曝光记录
    @SerializedName("download_type")
    var downloadType: String? = "",

    // 用来标记下载完成的类型，仅用于曝光记录
    @SerializedName("download_complete_type")
    var downloadCompleteType: String? = "",

    // 游戏版本 （本地字段），供下载统计使用
    var gameVersion: String = "",

    // 本地字段，使用镜像信息
    var useMirrorInfo: Boolean = false,
    // 本地字段，已使用的镜像实体，一旦存在便不再变更
    var cachedMirrorData: GameEntity? = null,

    // 本地字段，最后打开时间
    var lastPlayedTime: Long = 0,

    // 本地字段，曝光用
    @SerializedName("display_content")
    var displayContent: String = "",
    var isPlatformRecommend: Boolean = false,
    // 从启动弹窗跳转到对应游戏列表时候记录的启动弹窗数据 (ugly ugly ugly)
    var welcomeDialogId: String? = null,
    var welcomeDialogTitle: String? = null,

    // 专题id，用于曝光使用
    var subjectId: String? = null,
    // 专题名字，用于曝光使用
    var subjectName: String? = null,
    // 外层页面 id ，用于曝光使用
    var containerId: String? = null,
    // 外层页面类型，用于曝光使用
    var containerType: String? = null,

    // 游戏分类，用于埋点使用
    var gameType: String = "",
    //游戏存档 需要使用
    var configUrl: String = "",
    //是否广告，用于曝光使用
    var isAdData: Boolean = false,
    //广告位ID，用于曝光使用
    var adSpaceId: String = "",
    //广告源计划ID，用于曝光使用
    var gameAdSourceId: String = "",
    //游戏详情大家都在玩推荐类型：标签推荐/下载推荐/安装推荐，用于曝光使用
    var recommendType: String = "",
    // 广告组 id (存在且不为空表示该游戏为广告游戏)
    @SerializedName("ad_group_id")
    var adGroupId: String = "",
    // 后台设置的位置序号
    @SerializedName("backend_sequence")
    var backendSequence: Int = -1,

    var subPageId: String? = null, // 子页面 id
    var subPageCode: String? = null, // 子页面 code

    @SerializedName("selling_points_text")
    var sellingPointsText: String = "", // 卖点文案
    @SerializedName("game_tags")
    var gameTags: ArrayList<TagStyleEntity> = ArrayList(),
    @SerializedName("selling_point_tags")
    var sellingPointTags: ArrayList<TagStyleEntity> = ArrayList(),

    @SerializedName("welfare_text")
    var welfareText: WelfareText? = null, // 福利游戏文案
    var event: List<BigEvent>? = null, // 游戏大事件（如果事件时间为今日，且今日有多条大事件，则返回今日全部大事件）
    @SerializedName("official_entry")
    var officialEntry: Boolean = false, // 官方入驻标识

    // 临时变量：dsp游戏专用
    var dspAdId: String = "",
    val developer: String? = null,
    val permissionsUrl: String? = null,
    val privacyUrl: String? = null,
    val interactionType: Int = -1, // 交互类型: 下载应用 = 2 ; 拉起微信小程序/小游戏 = 4
    var searchKey: String? = null, // 搜索关键字，仅在搜索页面可能存在
    var tempDspLogMap: Map<String, String>? = null,

    val showUrl: String? = null, // 广告展示在用户界面上后触发
    val clickUrl: String? = null, // 广告被点击后触发
    val downloadUrl: String? = null, // 广告被下载后触发
    val installUrl: String? = null, // 广告被安装后触发
    var isDspGame: Boolean = false,
) : Parcelable {

    constructor(id: String?) : this() {
        this._id = id ?: "empty gameId"
    }

    constructor(id: String?, name: String?) : this() {
        this._id = id ?: "empty gameId, it's name is $name"
        this.mName = name
    }

    // 自定义页面位置信息，用于埋点
    @IgnoredOnParcel
    var customPageTrackData: CustomPageTrackData? = null

    // 曝光来源，用于埋点
    @IgnoredOnParcel
    var exposureSource: List<ExposureSource>? = null

    @IgnoredOnParcel
    var lastAcctGame: AcctGameInfo? = null

    // 临时变量
    @IgnoredOnParcel
    var hasBubbleShowed = false

    val assignRemark: AssignRemark
        get() = _assignRemark ?: AssignRemark()

    var id: String
        set(value) {
            _id = value
        }
        get() = if (isWechatMiniGameCPM()) miniGameAppId else _id

    @IgnoredOnParcel
    private var entryMap: androidx.collection.ArrayMap<String, DownloadEntity>? =
        androidx.collection.ArrayMap()

    @IgnoredOnParcel
    var gameLocation: GameLocation? = null

    // 曝光事件，若本 gameEntity 被 itemData 包裹请将曝光事件放置于外层的 itemData
    @IgnoredOnParcel
    var exposureEvent: ExposureEvent? = null

    @IgnoredOnParcel
    var testTime: String? = "" // 开测时间

    @IgnoredOnParcel
    var briefStyle: String? = "" // 本地处理得到的简介显示配置

    @IgnoredOnParcel
    private var mValidApkList: ArrayList<ApkEntity>? = null // 有效的 apk 列表，避免重复调用

    @IgnoredOnParcel
    private var mLastMirrorUpdatedTime: Long = 0 // 上一次检查镜像的时间

    @IgnoredOnParcel
    private var mIsVGame: Boolean = false

    @IgnoredOnParcel
    private var mGameDownloadButtonMode: Int = GAME_DOWNLOAD_BUTTON_MODE_UNKNOWN // 游戏下载按钮模式 (仅下载、仅畅玩、双下载)

    @IgnoredOnParcel
    var name: String?
        get() = if (shouldUseMirrorInfo()) {
            obtainMirrorData()?.mName?.removeSuffix(".") ?: "mirror unknown"
        } else {
            mName?.removeSuffix(".") ?: "unknown"
        }
        set(value) {
            mName = value
        }

    /**
     * 获取镜像数据
     */
    fun obtainMirrorData(): GameEntity? {
        if (cachedMirrorData != null) {
            return cachedMirrorData
        }

        val regionSettingProvider = TheRouter.get(IRegionSettingHelperProvider::class.java)

        return when (regionSettingProvider?.getMirrorPosition(_id)) {
            1 -> mMirrorData
            2 -> mMirrorData2
            else -> null
        }?.also { cachedMirrorData = it }
    }

    @IgnoredOnParcel
    var recommendText: String
        get() = if (isWechatMiniGame() || isWechatMiniGameCPM()) {
            brief ?: ""
        } else {
            _recommendText
        }
        set(value) {
            _recommendText = value
        }

    @IgnoredOnParcel
    val explainText: String
        get() = _explainText ?: ""

    @IgnoredOnParcel
    var h5Link: LinkEntity?
        get() = if (shouldUseMirrorInfo()) {
            obtainMirrorData()?.mH5Link
        } else mH5Link
        set(value) {
            mH5Link = value
        }

    @IgnoredOnParcel
    var downloadOffStatus: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mDownloadOffStatus else mDownloadOffStatus
        set(value) {
            mDownloadOffStatus = value
        }

    @IgnoredOnParcel
    var downloadOffDialog: Dialog?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mDownloadOffDialog else mDownloadOffDialog
        set(value) {
            mDownloadOffDialog = value
        }

    @IgnoredOnParcel
    var isReservable: Boolean
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mReservable ?: false else mReservable
        set(value) {
            mReservable = value
        }

    @IgnoredOnParcel
    var icon: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mIcon else mIcon
        set(value) {
            mIcon = value
        }

    @IgnoredOnParcel
    var rawIcon: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mRawIcon else mRawIcon
        set(value) {
            mRawIcon = value
        }

    @IgnoredOnParcel
    var iconSubscript: String?
        get() = if (ContentBlockedHelper.isContentBlocked(ContentBlockedHelper.ICON_SUBSCRIPT)) {
            ""
        } else {
            if (shouldUseMirrorInfo()) obtainMirrorData()?.mIconSubscript else mIconSubscript
        }
        set(value) {
            mIconSubscript = value
        }

    @IgnoredOnParcel
    var iconFloat: IconFloat?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mIconFloat else mIconFloat
        set(value) {
            mIconFloat = value
        }

    @IgnoredOnParcel
    var category: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mCategory else mCategory
        set(value) {
            mCategory = value
        }

    @IgnoredOnParcel
    val categoryChinese: String
        get() = when (category) {
            "online" -> "网络"
            "local" -> "单机"
            "welfare" -> "福利"
            "simulator" -> "模拟器"
            else -> category ?: ""
        }

    @IgnoredOnParcel
    var brief: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mBrief else mBrief
        set(value) {
            mBrief = value
        }

    @IgnoredOnParcel
    var subtitle: String
        get() = if (ContentBlockedHelper.isContentBlocked(ContentBlockedHelper.SUBTITLE)) {
            ""
        } else {
            if (shouldUseMirrorInfo()) obtainMirrorData()?.mSubtitle ?: "" else mSubtitle
        }
        set(value) {
            mSubtitle = value
        }

    @IgnoredOnParcel
    var subtitleStyle: TagStyleEntity?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mSubtitleStyle else mSubtitleStyle
        set(value) {
            mSubtitleStyle = value
        }

    @IgnoredOnParcel
    var advanceDownload: Boolean
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mAdvanceDownload ?: false else mAdvanceDownload
        set(value) {
            mAdvanceDownload = value
        }

    @IgnoredOnParcel
    var hideSizeInsideDes: Boolean = false

    @IgnoredOnParcel
    val decoratedDes: String?
        get() = if (
            getApk().size > 0
            && !hideSizeInsideDes
            && ((TextUtils.isEmpty(subjectData?.briefStyle)
                    || subjectData?.briefStyle?.contains("size") == true)
                    || subjectData?.briefStyle?.contains("recommend") == true)
        ) {
            getApk().firstOrNull()?.size + "  " + brief
        } else {
            brief
        }

    @IgnoredOnParcel
    val downloadOffText: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mDownloadOffText else mDownloadOffText

    @IgnoredOnParcel
    var tagStyle: ArrayList<TagStyleEntity>
        get() = if (ContentBlockedHelper.isContentBlocked(ContentBlockedHelper.GAME_TAG)) {
            arrayListOf()
        } else {
            if (shouldUseMirrorInfo()) obtainMirrorData()?.mTagStyle?.apply {
                removeAll {
                    it.name.toLowerCase(
                        Locale.getDefault()
                    ) == "mod版"
                }
            } ?: arrayListOf() else mTagStyle
        }
        set(value) {
            mTagStyle = value
        }

    /**
     * 是否为 mod 游戏，根据是否有 mod 标签来判断，不受镜像、游戏屏蔽影响
     */
    @IgnoredOnParcel
    val isModdedGame: Boolean
        get() = mTagStyle.any { it.name.lowercase(Locale.getDefault()) == "mod" }

    @IgnoredOnParcel
    val downloadAddWord: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mDownloadAddWord else mDownloadAddWord

    @IgnoredOnParcel
    val versionNumber: String?
        get() = if (shouldUseMirrorInfo()) obtainMirrorData()?.mVersionNumber else mVersionNumber

    @IgnoredOnParcel
    val downloadStatusChinese: String
        get() = when (downloadStatus) {
            "on" -> "开启"
            Constants.V_GAME, Constants.V_GAME_32 -> "畅玩"
            "appointment" -> "预约"
            "demo" -> "试玩"
            else -> ""
        }

    @IgnoredOnParcel
    val gameBit: String
        get() = if (getApk().isNotEmpty()) {
            getApk()[0].bit
        } else ""

    @IgnoredOnParcel
    val gameBitChinese: String
        get() = if (gameBit == "32") "32位" else "64位"

    @IgnoredOnParcel
    val abbreviation: String
        get() = _abbreviation ?: ""

    @IgnoredOnParcel
    val wifiAutoDownload
        get() = _wifiAutoDownload ?: false

    // 广告游戏填充日志是否已经上报
    @IgnoredOnParcel
    var isAdRequestReported = false

    @IgnoredOnParcel
    var pageLevelString: String = ""

    // 游戏是否有 wifi自动下载功能
    val wifiAutoDownloadEnable: Boolean
        get() = _wifiAutoDownload != null

    private var acceleratorStatus: Boolean
        get() = _acceleratorStatus ?: false
        set(value) {
            _acceleratorStatus = value
        }

    var serviceArea: List<AcctGameInfo.ZoneInfo>
        get() = _serviceArea ?: emptyList()
        set(value) {
            _serviceArea = value
        }

    // 配置了加速并且只有一个apk包
    val canSpeed: Boolean
        get() = acceleratorStatus && getApk().size == 1 && serviceArea.isNotEmpty()

    @IgnoredOnParcel
    val appointmentCount: Int
        get() = _appointmentCount ?: 0


    //是否需要弹出试玩弹窗
    fun isShowVersionNumber(): Boolean {
        return versionNumber == "无版号无内购有弹窗"
    }

    //是获取试玩弹窗提示文案
    fun getVersionNumberString(): String {
        return when (versionNumber) {
            "无版号有内购" -> HaloApp.getInstance().getString(com.gh.gamecenter.common.R.string.attempt_tips_1)
            "无版号无内购有弹窗" -> HaloApp.getInstance().getString(com.gh.gamecenter.common.R.string.attempt_tips_2)
            else -> ""
        }
    }

    fun setWelcomeDialogInfoIfAvailable() {
        val appProvider = TheRouter.get(IAppProvider::class.java)
        welcomeDialogId = appProvider?.get(Constants.WELCOME_DIALOG_ID, false) as? String
        welcomeDialogTitle = appProvider?.get(Constants.WELCOME_DIALOG_LINK_TITLE, false) as? String
    }

    fun getApk(): ArrayList<ApkEntity> {
        if (mValidApkList == null || shouldApkReCheckMirrorInfo()) {
            if (shouldUseMirrorInfo()) return obtainMirrorData()?.getApk() ?: arrayListOf()

            var rawApk = apk ?: ArrayList()
            if (gameLocation == GameLocation.INDEX && mApkIndex != null) {
                rawApk = mApkIndex!!
            } else if (gameLocation == GameLocation.SEARCH && mApkSearch != null) {
                rawApk = mApkSearch!!
            }

            mValidApkList = rawApk

            mLastMirrorUpdatedTime = System.currentTimeMillis()
        }

        return mValidApkList!!
    }

    /**
     * 获取唯一的包名，仅单版本游戏有效，多版本的游戏请不要调用
     */
    fun getUniquePackageName(): String? {
        return getApk().firstOrNull()?.packageName
    }

    fun getUniquePlatform(): String? {
        return getApk().firstOrNull()?.getPlatform()
    }

    fun getOriginalApk(): ArrayList<ApkEntity> {
        if (apk == null) apk = ArrayList()
        return apk!!
    }

    fun setApk(apk: ArrayList<ApkEntity>?) {
        this.apk = apk
    }

    /**
     * 丢弃 apk 以外的 apkIndex、apkSearch、apkLink
     */
    fun dropOtherApk() {
        mApkIndex = arrayListOf()
        mApkSearch = arrayListOf()
        apkLink = arrayListOf()
        mValidApkList = null
    }

    fun getEntryMap(): androidx.collection.ArrayMap<String, DownloadEntity> {
        return entryMap!!
    }

    fun getRawIconInAdvanced(): String {
        return rawIcon ?: icon ?: ""
    }

    fun setEntryMap(entryMap: androidx.collection.ArrayMap<String, DownloadEntity>?) {
        if (entryMap != null) {
            this.entryMap = entryMap
        }
    }

    fun getGameCategory(): GameCategory {
        return when {
            isWelfareGame() -> GameCategory.WELFARE_GAME
            isOnlineGame() -> GameCategory.ONLINE_GAME
            isLocalGame() -> GameCategory.LOCAL_GAME
            isInternationalLocalGame() -> GameCategory.INTERNATIONAL_LOCAL_GAME
            isInternationalOnlineGame() -> GameCategory.INTERNATIONAL_ONLINE_GAME
            else -> GameCategory.LOCAL_GAME
        }
    }

    fun setIsPlatformRecommend(isPlatformRecommend: Boolean) {
        this.isPlatformRecommend = isPlatformRecommend
    }

    /**
     * 游戏所属类型
     * 网络游戏：category 为 online 的游戏
     * 单机游戏：category 为 local 的游戏
     * 福利游戏：category 为 welfare 的游戏
     */
    private fun isOnlineGame(): Boolean {
        return category.equals("online")
    }

    private fun isLocalGame(): Boolean {
        return category.equals("local")
    }

    private fun isWelfareGame(): Boolean {
        return category.equals("welfare")
    }

    private fun isInternationalLocalGame(): Boolean {
        return category.equals("gjlocal")
    }

    private fun isInternationalOnlineGame(): Boolean {
        return category.equals("gjonline")
    }

    val miniGameType: String
        get() = when (profit) {
            Constants.WECHAT_MINI_GAME_PROFIT_CPM -> Constants.WECHAT_MINI_GAME_CPM
            Constants.DSP_GAME -> Constants.DSP_GAME
            else -> miniGameCategory
        }

    /**
     * 当前游戏是否为小游戏
     */
    fun isMiniGame(): Boolean = miniGameAppId.isNotEmpty()

    /**
     * 当前游戏是否为QQ小游戏
     */
    fun isQQMiniGame(): Boolean = isMiniGame() && miniGameType == Constants.QQ_MINI_GAME

    /**
     * 当前游戏是否为微信小游戏
     */
    fun isWechatMiniGame(): Boolean = isMiniGame() && miniGameType == Constants.WECHAT_MINI_GAME

    /**
     * 当前游戏是否为微信小游戏CPM
     */
    fun isWechatMiniGameCPM(): Boolean = isMiniGame() && miniGameType == Constants.WECHAT_MINI_GAME_CPM

    /**
     * 当前小游戏是否下架
     */
    fun isMiniGameOffShelve(): Boolean = miniGameAppStatus == 1

    /**
     * 是否需要重新检查镜像中的 apk 信息
     * 当 useMirrorInfo 的值为 true 时，就不重新检查了，维持镜像的打开状态
     * 仅当 useMirrorInfo 的值为 false 时，为了避免一直卡在镜像的关闭状态，才去重新检查
     */
    private fun shouldApkReCheckMirrorInfo(): Boolean {
        if (!useMirrorInfo
            && System.currentTimeMillis() - mLastMirrorUpdatedTime > CHECK_MIRROR_INFO_INTERVAL
        ) {
            return true
        }

        return false
    }

    fun shouldUseMirrorInfo(): Boolean {
        if (useMirrorInfo) {
            return true
        } else {
            val provider = TheRouter.get(IRegionSettingHelperProvider::class.java)
            useMirrorInfo =
                (mirrorStatus == "on" && mMirrorData != null) && provider?.getMirrorPosition(_id) == 1
                        || (mirrorStatus2 == "on" && mMirrorData2 != null) && provider?.getMirrorPosition(_id) == 2
        }

        return useMirrorInfo
    }

    /**
     * 获取镜像的序号
     * @return -1 代表没有使用镜像， 1 代表使用镜像 1，2 代表使用镜像 2
     */
    fun getMirrorPosition(): Int {
        val provider = TheRouter.get(IRegionSettingHelperProvider::class.java)

        return provider?.getMirrorPosition(_id) ?: -1
    }

    /**
     * 获取游戏下载按钮模式，包括单按钮显示、双按钮显示等模式
     *
     * 根据 download_status 和 download_extra_status 字段来确认模式
     * download_status	        download_extra_status	        下载按钮
     * on	                    off	                            本地
     * on	                    smooth/smooth_32	            本地 + 畅玩
     * smooth/smooth_32	        on	                            本地 + 畅玩
     * smooth/smooth_32	        off	                            畅玩
     * off/demo/link/appointment	 	                        本地
     *
     * GAME_DOWNLOAD_BUTTON_TYPE_DOWNLOAD   仅本地
     * GAME_DOWNLOAD_BUTTON_TYPE_VGAME      仅畅玩
     * GAME_DOWNLOAD_BUTTON_TYPE_DUAL       本地 + 畅玩
     *
     * 2024-01-16新增：当处于兼职包特殊渠道（GH_jzcs）且只有一个APK时，强行开启双按钮显示
     * https://jira.shanqu.cc/browse/GHZS-4520
     */
    fun getGameDownloadButtonMode(): Int {
        if (mGameDownloadButtonMode == GAME_DOWNLOAD_BUTTON_MODE_UNKNOWN) {
            val vHelperProvider = TheRouter.get(IVHelperProvider::class.java)
            val haloAppProvider = TheRouter.get(IAppProvider::class.java)
            mGameDownloadButtonMode = when {

                haloAppProvider?.getChannel() == "GH_jzcs" && getApk().size == 1 -> {// 兼职包特殊渠道且只有一个APK时，强行开启双按钮显示
                    GAME_DOWNLOAD_BUTTON_MODE_DUAL
                }

                vHelperProvider?.isVGameOn() == false
                        || downloadStatus == "off"
                        || downloadStatus == "demo"
                        || downloadStatus == "link"
                        || downloadStatus == "appointment" -> {
                    GAME_DOWNLOAD_BUTTON_MODE_DOWNLOAD
                }

                downloadStatus == "on" && mDownloadStatusExtra.contains("smooth") -> {
                    GAME_DOWNLOAD_BUTTON_MODE_DUAL
                }

                downloadStatus?.contains("smooth") == true && mDownloadStatusExtra == "on" -> {
                    GAME_DOWNLOAD_BUTTON_MODE_DUAL
                }

                downloadStatus?.contains("smooth") == true
                        && (mDownloadStatusExtra == "off" || mDownloadStatusExtra == "") -> {
                    GAME_DOWNLOAD_BUTTON_MODE_VGAME
                }

                else -> GAME_DOWNLOAD_BUTTON_MODE_DOWNLOAD
            }
        }

        return mGameDownloadButtonMode
    }

    /**
     * 畅玩是否优先级更高
     */
    fun isVGamePreferred(): Boolean {
        return when (getGameDownloadButtonMode()) {
            GAME_DOWNLOAD_BUTTON_MODE_DOWNLOAD -> false
            GAME_DOWNLOAD_BUTTON_MODE_VGAME -> true
            GAME_DOWNLOAD_BUTTON_MODE_DUAL -> mDefaultDownloadType.contains(Constants.V_GAME)

            else -> false
        }
    }

    /**
     * 双下载按钮模式是否启用
     */
    fun isDualBtnModeEnabled(): Boolean {
        return getGameDownloadButtonMode() == GAME_DOWNLOAD_BUTTON_MODE_DUAL
    }

    /**
     * 强制变成单下载按钮模式，且为本地下载 (谨慎使用！)
     */
    fun forceToBeDownloadModeOnly() {
        mGameDownloadButtonMode = GAME_DOWNLOAD_BUTTON_MODE_DOWNLOAD
        downloadStatus = "on"
        mDownloadStatusExtra = "off"
    }

    /**
     * 是否是畅玩游戏 （当且仅当畅玩开关打开，且游戏类型为畅玩才会返回 true）
     */
    @Deprecated("只用来兼容旧的数据，新的功能不要调用它")
    fun isVGame(): Boolean {
        if (!mIsVGame) {
            val vHelperProvider = TheRouter.get(IVHelperProvider::class.java)
            mIsVGame = if (vHelperProvider?.isVGameOn() == false) {
                false
            } else if (mDownloadStatusExtra == "off") {
                downloadStatus == Constants.V_GAME || downloadStatus == Constants.V_GAME_32
            } else {
                false
            }
        }

        return mIsVGame
    }

    fun isSplitXApk(): Boolean {
        val apkList = getApk()
        if (apkList.isEmpty()) return false
        return apkList[0].format == Constants.XAPK_APKS_FORMAT
    }

    fun isUseDefaultServerStyle(): Boolean {
        return if (serverLabel == null) {
            false
        } else {
            serverLabel?.value == "公测"
                    || serverLabel?.value == "不删档内测"
                    || serverLabel?.value == "删档内测"
                    || serverLabel?.value == "即将开测"
                    || serverLabel?.value == "明日开测"
        }
    }

    fun isSpecialDownload(): Boolean {
        val provider = TheRouter.get(IRegionSettingHelperProvider::class.java)
        return provider?.shouldThisGameShowSpecialDownload(_id) == true
    }

    /**
     * 是否为海外地址下载游戏
     */
    fun isOverseaAddressDialog(): Boolean = !isLandPageAddressDialog()
            && getApk().size != 0
            && overseasAddressDialog?.let { it.status == "show" || it.status == "show&download" } ?: false

    /**
     * 是否为第三方落地页跳转游戏
     */
    fun isLandPageAddressDialog(): Boolean = landPageAddressDialog?.let { it.status == "on" } ?: false

    /**
     * 第三方落地页的状态是否为“仅显示弹窗”
     */
    fun isLandPageAddressDialogShowOnly(): Boolean = landPageAddressDialog?.showOnly == true

    /**
     * 设置镜像数据
     * @param position 镜像1 or 镜像2
     */
    fun setMirrorData(position: Int, mirrorData: GameEntity?) {
        if (position == 1) {
            mMirrorData = mirrorData
        } else if (position == 2) {
            mMirrorData2 = mirrorData
        }
    }

    fun getTypeName() =
        when (type) {
            "filter" -> "算法过滤"
            "recommend" -> "专题推荐"
            "ad" -> "游戏广告"
            else -> ""
        }

    fun toSimpleGame(): SimpleGame {
        val simpleGame = SimpleGame()
        simpleGame.id = _id
        simpleGame.mName = mName
        simpleGame.mIcon = mIcon
        simpleGame.mRawIcon = mRawIcon
        simpleGame.active = active
        simpleGame.iconSubscript = iconSubscript
        simpleGame.recommendStar = recommendStar
        simpleGame.recommendText = recommendText
        return simpleGame
    }

    fun convertSimulatorGameRecordEntity(): SimulatorGameRecordEntity {
        val entity = SimulatorGameRecordEntity()
        entity.id = _id
        entity.brief = brief
        entity.des = des
        entity.icon = rawIcon
        entity.iconSubscript = iconSubscript
        entity.name = name
        entity.tagStyle = tagStyle
        entity.simulatorType = simulatorType
        entity.simulator = simulator
        entity.category = category ?: ""
        entity.isRecentlyPlayed = isRecentlyPlayed
        entity.apk = getApk()
        return entity
    }

    val showImage: Boolean
        get() {
            if (!DISPLAY_CONTENT_IMAGE.equals(displayContent, true) && topVideo != null) {
                return false
            }
            return (isWechatMiniGame() && banner.isNotBlank()) || homeSetting.image.isNotBlank()
        }

    companion object {
        const val CHECK_MIRROR_INFO_INTERVAL = 10 * 1000 // 检查镜像更新间隔 10s

        private const val GAME_DOWNLOAD_BUTTON_MODE_UNKNOWN = 0
        const val GAME_DOWNLOAD_BUTTON_MODE_DOWNLOAD = 1
        const val GAME_DOWNLOAD_BUTTON_MODE_VGAME = 2
        const val GAME_DOWNLOAD_BUTTON_MODE_DUAL = 3

        private const val DISPLAY_CONTENT_IMAGE = "image"
    }

    @Parcelize
    class Dialog(
        var title: String = "",
        var content: String = "",
        var sites: List<Site> = listOf(),
        @SerializedName("close_button_text")
        var closeButtonText: String = "",
        @SerializedName("confirm_button")
        var confirmButton: LinkEntity = LinkEntity(),
        var rule: Rule = Rule(),
        // 值可能是 ONCE_A_DAY / EVERY_TIME_OPEN
        var alert: String = ""
    ) : Parcelable {
        @Parcelize
        class Rule(
            @SerializedName("package")
            var packageName: String = "",
            var models: ArrayList<String> = arrayListOf(),
            @SerializedName("system_versions")
            var systemVersions: ArrayList<String> = arrayListOf(),
            @SerializedName("notice_versions")
            var noticeVersions: ArrayList<String> = arrayListOf()
        ) : Parcelable

        @Parcelize
        class Site(
            var url: String = "",
            var text: String = ""
        ) : Parcelable
    }

    @Parcelize
    class PluginLink(
        @SerializedName("link_id")
        var linkId: String = "",
        var title: String = "",
        @SerializedName("link_type")
        var linkType: String = "", // article,Q&A,dialog
        @SerializedName("link_text")
        var linkText: String = "",
        var content: String = "",
        @SerializedName("link_community")
        var community: CommunityEntity? = CommunityEntity(),
        var display: Display? = null
    ) : Parcelable {

        fun getLinkEntity(): LinkEntity {
            return LinkEntity(
                link = linkId,
                title = title,
                type = linkType,
                text = linkText,
                community = community,
                display = display
            )
        }
    }

    @Parcelize
    class AddressDialog(
        var status: String? = "",
        var link: String? = "",
        @SerializedName("show_only")
        var showOnly: Boolean? = false
    ) : Parcelable

    // 游戏位置， 根据游戏位置只显示某个单独的APK
    enum class GameLocation {
        INDEX,
        SEARCH,
    }

    enum class GameCategory(val value: String) {
        ONLINE_GAME("online_game"),
        LOCAL_GAME("local_game"),
        WELFARE_GAME("welfare_game"),
        INTERNATIONAL_LOCAL_GAME("gjlocal_game"),
        INTERNATIONAL_ONLINE_GAME("gjonline_game");

        override fun toString() = value
    }

    @Parcelize
    class AssignRemark(
        @SerializedName("first_line")
        val firstLine: String = "",
        @SerializedName("second_line")
        val secondLine: String = "",
        @SerializedName("marked_red")
        val markedRed: Boolean = false,
        val recommend: Boolean = false,
        @SerializedName("start_time")
        val startTime: Long = 0,
        @SerializedName("end_time")
        val endTime: Long = 0
    ) : Parcelable

    @Parcelize
    data class ContentTag(
        val custom: List<CustomTag> = listOf(),
        @SerializedName("zone_setting")
        val zone: ZoneEntity = ZoneEntity(),
        @SerializedName("ling_libao_exists")
        val isLibaoExists: Boolean = false,
        val server: Boolean = false,
        @SerializedName("bbs_exists")
        val isBbsExists: Boolean = false
    ) : Parcelable

    @Parcelize
    class CustomTag(
        @SerializedName("_id")
        val id: String = "",
        val text: String = "",
        val link: LinkEntity = LinkEntity(),
        val icon: Icon = Icon()
    ) : Parcelable {

        @Parcelize
        class Icon(
            @SerializedName("_id")
            var id: String = "",
            var name: String = "",
            var url: String = ""
        ) : Parcelable
    }

    @Parcelize
    class ColumnRank(
        val name: String = "",
        val position: Int = 0
    ) : Parcelable

    @Parcelize
    class WelfareText(
        val status: String = "", // 福利文案显示状态,on/off，当status=on时，app不展示comment_star游戏评分
        val text: String = "", // 福利文案
        val discount: String = "", // 折扣信息
    ) : Parcelable

    @Parcelize
    class SellingPoints(
        @SerializedName("text")
        private val _text: String? = null,
        @SerializedName("start")
        private val _start: Long? = null,
        @SerializedName("end")
        private val _end: Long? = null
    ) : Parcelable {

        val text: String
            get() = _text ?: ""

        val start: Long
            get() = _start ?: 0

        val end: Long
            get() = _end ?: 0
    }
}

@Parcelize
class SimpleGame(
    @SerializedName("_id")
    var id: String? = null,
    @SerializedName("name")
    var mName: String? = "",
    @SerializedName("icon")
    var mIcon: String? = null,
    @SerializedName("ori_icon")
    var mRawIcon: String? = null,
    @SerializedName("icon_subscript")
    private var mIconSubscript: String? = null,
    var active: Boolean = false,
    //游戏单推荐分数
    @SerializedName("recommend_star")
    var recommendStar: Int = 5,
    @SerializedName("mirror_status")
    var mirrorStatus: String? = "",
    @SerializedName("mirror_data")
    var mirrorData: SimpleGame? = null,
    @SerializedName("mirror_status2")
    var mirrorStatus2: String? = "",
    @SerializedName("mirror_data2")
    var mirrorData2: SimpleGame? = null,
    //游戏单推荐理由
    @SerializedName("recommend_text")
    var recommendText: String = "",
    @SerializedName("download_status")
    var downloadStatus: String = "",

    var subtitle: String? = "",
    @SerializedName("subtitle_style")
    var subtitleStyle: TagStyleEntity? = null,
    @SerializedName("advance_download")
    var advanceDownload: Boolean = false,
    @SerializedName("icon_float")
    var iconFloat: IconFloat? = null,
    var category: String? = null,
    @SerializedName("home_setting_image")
    var homeSettingImage: String = "", // 游戏大图
) : Parcelable {

    @IgnoredOnParcel
    var iconSubscript: String?
        get() = if (ContentBlockedHelper.isContentBlocked(ContentBlockedHelper.ICON_SUBSCRIPT)) {
            ""
        } else {
            mIconSubscript
        }
        set(value) {
            mIconSubscript = value
        }

    @IgnoredOnParcel
    val name: String?
        get() = mName?.removeSuffix(".")

    fun getIcon(): String {
        return mRawIcon ?: mIcon ?: ""
    }

    fun getDefaultIcon(): String {
        return mIcon ?: ""
    }

    @IgnoredOnParcel
    var testTime: String? = "" // 开测时间

    @IgnoredOnParcel
    val categoryChinese: String
        get() = when (category) {
            "online" -> "网络"
            "local" -> "单机"
            "welfare" -> "福利"
            "simulator" -> "模拟器"
            else -> category ?: ""
        }

    fun toGameEntity(): GameEntity {
        val gameEntity = GameEntity(id = id, name = name)
        gameEntity.icon = mIcon
        gameEntity.rawIcon = mRawIcon
        gameEntity.iconSubscript = iconSubscript
        gameEntity.mirrorStatus = mirrorStatus
        gameEntity.mirrorStatus2 = mirrorStatus2
        gameEntity.setMirrorData(1, mirrorData?.toGameEntity())
        gameEntity.setMirrorData(2, mirrorData2?.toGameEntity())
        gameEntity.recommendStar = recommendStar
        gameEntity.recommendText = recommendText
        gameEntity.downloadStatus = downloadStatus
        gameEntity.subtitle = subtitle ?: ""
        gameEntity.subtitleStyle = subtitleStyle
        gameEntity.advanceDownload = advanceDownload
        gameEntity.iconFloat = iconFloat
        gameEntity.category = category
        gameEntity.testTime = testTime
        return gameEntity
    }

    fun toCommunityGameEntity(): CommunityEntity.CommunityGameEntity {
        val gameEntity = CommunityEntity.CommunityGameEntity(id = id, mName = name)
        gameEntity.mIcon = mIcon
        gameEntity.mRawIcon = mRawIcon
        gameEntity.iconSubscript = iconSubscript
        gameEntity.iconFloat = iconFloat
        gameEntity.category = category
        return gameEntity
    }
}
