import Actions from "./enum/Actions.js"
import {eventsManager} from "./EventsManager.js"
import util from "./util.js"
import Person from "./enum/Person.js"
import ClickType from "./enum/ClickType.js"
import Logger from "./Logger.js"

const logger = new Logger('actions-handler')
const QueueActions = [Actions.Transfer, Actions.ChangeSkin, Actions.GetOnVehicle, Actions.GetOffVehicle];
export default class ActionsHandler {
    constructor(e) {
        this.currentActiveAction = null
        this.room = e
    }

    async avatarComponentsSync(e){
        const t = {
            action_type: Actions.SetPlayerState,
            set_player_state_action: {
                player_state: {
                    avatar_components: JSON.stringify(e)
                }
            }
        };
        this.sendData({
            data: t
        })
    }

    async sendData(actionData) {
        await this.beforeSend(actionData);
        const traceId = util.uuid();
        this.room.networkController.sendRtcData(le(oe({}, actionData.data), {
            trace_id: traceId,
            user_id: this.room.options.userId
        }));

        if (actionData.track === !1)
        {
            return Promise.resolve(null);
        }
        const { sampleRate=1, timeout=2e3, tag, data, special } = actionData;
        return eventsManager.track({
            timeout,
            traceId,
            event: data.action_type,
            tag,
            extra: data
        }, {
            special,
            sampleRate,
            noReport: this.room.viewMode === "serverless" || this.room.options.viewMode === "serverless"
        }).finally(()=>{
            QueueActions.includes(actionData.data.action_type) && (this.currentActiveAction = void 0)
        })
    }

    async beforeSend(e) {
        var o;
        const t = (o = this.room._userAvatar) == null ? void 0 : o.isMoving
          , r = e.data.action_type;
        if (QueueActions.includes(r)) {
            if (this.currentActiveAction)
                return logger.error(`${Actions[this.currentActiveAction]} still pending, reject ${Actions[r]}`),
                Promise.reject(new FrequencyLimitError(`${Actions[r]} action request frequency limit`));
            this.currentActiveAction = r
        }
        if (t && QueueActions.includes(e.data.action_type))
            try {
                await this.stopMoving()
            } catch (a) {
                this.currentActiveAction = void 0,
                logger.error("before action stopMoving failed", a)
            }
    }
    async moveTo(e) {
        const {point: t, extra: r="", motionType: n} = e
          , o = {
            action_type: Actions.Clicking,
            clicking_action: {
                clicking_point: t,
                clicking_type: ClickType.IgnoreView,
                extra: encodeURIComponent(r),
                attitude: n
            },
            clicking_state: this.room._currentClickingState
        };
        return this.sendData({
            data: o
        })
    }
    transfer(e) {
        const {renderType: t, player: r, camera: n, areaName: o, attitude: a, pathName: s, person: l, noMedia: u, timeout: c, tag: h, special: f} = e
          , d = {
            data: {
                action_type: Actions.Transfer,
                transfer_action: {
                    render_type: t,
                    player: r,
                    camera: n,
                    areaName: o,
                    attitude: a,
                    pathName: s,
                    person: {
                        type: l
                    },
                    noMedia: u,
                    tiles: [0, 1, 2, 4]
                }
            },
            special: f,
            timeout: c || 4e3,
            tag: h
        };
        return this.sendData(d).then(_=>(typeof l != "undefined" && this.room.updateCurrentNetworkOptions({
            person: l,
            rotationRenderType: t
        }),
        _))
    }
    changeRotationRenderType(e) {
        const {renderType: t, player: r, camera: n, areaName: o, attitude: a, pathName: s} = e;
        return this.transfer({
            renderType: t,
            player: r,
            camera: n,
            areaName: o,
            attitude: a,
            pathName: s,
            tag: "changeToRotationVideo"
        })
    }
    requestPanorama(e, noMedia, timeout) {
        const {camera: camera, player: player, areaName: areaName, attitude: attitude, pathName: pathName, tag: tag} = e;
        return this.transfer({
            renderType: RenderType.ClientRotationPano,
            player: player,
            camera: camera,
            person: Person.First,
            areaName: areaName,
            attitude: attitude,
            pathName: pathName,
            noMedia: noMedia,
            timeout: timeout,
            tag: tag || "requestPanorama",
            special: !noMedia
        })
    }
    setMotionType(e) {
        return this.transfer({
            attitude: e,
            tag: "setMotionType"
        })
    }
    setNickName(e) {
        const t = {
            action_type: Actions.ChangeNickname,
            change_nickname_action: {
                nickname: e
            }
        };
        return this.sendData({
            data: t
        })
    }
    getReserveSeat({routeId: e, name: t}) {
        const r = {
            action_type: Actions.ReserveSeat,
            reserve_seat_action: {
                route_id: e,
                name: t
            }
        };
        return this.sendData({
            data: r
        })
    }
    getReserveStatus({routeId: e, name: t, need_detail: r}) {
        const n = {
            action_type: Actions.GetReserveStatus,
            get_reserve_status_action: {
                route_id: e,
                name: t,
                need_detail: r
            }
        };
        return this.sendData({
            data: n,
            timeout: 2e3
        }).then(o=>o.reserveDetail)
    }
    stopMoving() {
        const e = {
            action_type: Actions.StopMoving,
            stop_move_action: {}
        };
        return this.sendData({
            data: e
        })
    }
    getOnVehicle({routeId: e, name: t, camera: r}) {
        const n = {
            action_type: Actions.GetOnVehicle,
            get_on_vehicle_action: {
                route_id: e,
                name: t,
                camera: r
            }
        };
        return this.sendData({
            data: n
        })
    }
    getOffVehicle({renderType: e, player: t, camera: r}) {
        const n = {
            action_type: Actions.GetOffVehicle,
            get_off_vehicle_action: {
                render_type: e,
                player: t,
                camera: r
            }
        };
        return this.sendData({
            data: n
        })
    }
    confirmEvent(e) {
        const t = {
            action_type: Actions.ConfirmEvent,
            confirm_event_action: {
                id: e
            }
        };
        return this.sendData({
            data: t,
            track: !1
        })
    }
    echo(e) {
        const t = {
            action_type: Actions.Echo,
            echo_msg: {
                echoMsg: e
            }
        };
        return this.sendData({
            data: t,
            track: !1
        })
    }
    async changeSkin(e) {
        const t = e.special === void 0 ? e.renderType === RenderType.ClientRotationPano : e.special
          , {skinId: r, mode: n, landingType: o=LandingType.Stay, landingPoint: a, landingCamera: s, renderType: l, areaName: u, attitude: c, pathName: h, person: f, noMedia: d, timeout: _, roomTypeId: g=""} = e
          , m = this.room.skinList.filter(y=>y.id === r)[0];
        if (!m) {
            const y = `skin ${r} is invalid`;
            return logger.error(y),
            Promise.reject(new ParamError(y))
        }
        const v = {
            action_type: Actions.ChangeSkin,
            change_skin_action: {
                skinID: r,
                mode: n === ChangeMode.Preview ? ChangeMode.Preview : ChangeMode.Confirm,
                skin_data_version: r + m.versionId,
                landing_type: o,
                landing_point: a,
                landing_camera: s,
                render_wrapper: {
                    render_type: l
                },
                areaName: u,
                attitude: c,
                noMedia: d,
                person: f,
                pathName: h,
                roomTypeId: g
            }
        };
        return this.sendData({
            data: v,
            timeout: _ || 6e3,
            special: t
        }).then(async y=>{
            if (l === RenderType.ClientRotationPano && y) {
                const b = await this.room.modelManager.findRoute(r, h)
                  , {camera: T} = util.getRandomItem(b.birthPointList) || {};
                await this.room.panorama.handleReceivePanorama(y, T)
            }
            return this.handleChangeSkin(e)
        }
        ).catch(y=>d ? this.handleChangeSkin(e) : Promise.reject(y))
    }
    handleChangeSkin(e) {
        const {skinId: t, mode: r, renderType: n, areaName: o, attitude: a, pathName: s} = e;
        return this.room.sceneManager.staticmeshComponent.getCgMesh().show(),
        this.room.sceneManager.cameraComponent.switchToCgCamera(),
        this.room.engineProxy._updateSkinAssets(t).then(()=>{
            this.room.sceneManager.staticmeshComponent.getCgMesh().hide(),
            this.room.sceneManager.cameraComponent.switchToMainCamera(),
            this.room.pathManager.currentArea = o,
            logger.info("changeSkin _updateSkinAssets susccss"),
            this.room.updateCurrentNetworkOptions({
                pathName: s,
                attitude: a,
                areaName: o
            }),
            this.room.skinChangedHook(),
            this.room.emit("skinChanged", {
                skin: {
                    id: t
                },
                mode: r
            }),
            n === RenderType.ClientRotationPano && this.room.sceneManager.cameraComponent.allowMainCameraController()
        }
        )
    }
    rotate({pitch: e, yaw: t}) {
        var n;
        if (this.room.disableRotate || this.room.isPano || ((n = this.room._userAvatar) == null ? void 0 : n._isChangingComponentsMode))
            return;
        const r = {
            action_type: Actions.Rotation,
            rotation_action: {
                vertical_move: e,
                horizontal_move: -t
            }
        };
        this.sendData({
            data: r,
            sampleRate: .02
        })
    }
    turnTo(e) {
        const {point: t, timeout: r=2e3, offset: n=8} = e || {}
          , o = {
            action_type: Actions.TurnTo,
            turn_to_action: {
                turn_to_point: t,
                offset: n
            }
        };
        return this.sendData({
            data: o,
            timeout: r
        })
    }
    rotateTo(e) {
        const {point: t, offset: r=0, speed: n=3} = e || {}
          , o = {
            action_type: Actions.RotateTo,
            rotate_to_action: {
                rotate_to_point: t,
                offset: r,
                speed: n
            }
        };
        return this.sendData({
            data: o
        })
    }
    broadcast(e) {
        const {data: t, msgType: r=MessageHandleType.MHT_FollowListMulticast, targetUserIds: n} = e;
        if (r === MessageHandleType.MHT_CustomTargetSync && !Array.isArray(n))
            return Promise.reject(new ParamError(`param targetUserIds is required  when msgType is ${MessageHandleType[r]}`));
        const o = {
            action_type: Actions.Broadcast,
            broadcast_action: {
                data: JSON.stringify(t),
                user_id: this.room.options.userId,
                msgType: r
            }
        };
        return Array.isArray(n) && r === MessageHandleType.MHT_CustomTargetSync && (o.broadcast_action.target_user_ids = n),
        this.room.actionsHandler.sendData({
            data: o,
            tag: t.broadcastType
        })
    }
    getNeighborPoints(e) {
        const {point: t, containSelf: r=!1, searchRange: n=500} = e
          , o = {
            action_type: Actions.GetNeighborPoints,
            get_neighbor_points_action: {
                point: t,
                level: 1,
                containSelf: r,
                searchRange: n
            }
        };
        return this.sendData({
            data: o
        }).then(a=>a.nps)
    }
    playCG(e) {
        const t = {
            action_type: Actions.PlayCG,
            play_cg_action: {
                cg_name: e
            }
        };
        return this.sendData({
            data: t
        })
    }
    audienceToVisitor(e) {
        const {avatarId: t, avatarComponents: r, player: n, camera: o} = e
          , a = {
            action_type: Actions.AudienceChangeToVisitor,
            audienceChangeToVisitorAction: {
                avatarID: t,
                avatarComponents: r,
                player: n,
                camera: o
            }
        };
        return logger.debug("send data: audience to visitor"),
        this.sendData({
            data: a
        })
    }
    visitorToAudience(e) {
        const {renderType: t, player: r, camera: n, areaName: o, attitude: a, pathName: s, person: l, noMedia: u} = e
          , c = {
            action_type: Actions.VisitorChangeToAudience,
            visitorChangeToAudienceAction: {
                transferAction: {
                    render_type: t,
                    player: r,
                    camera: n,
                    areaName: o,
                    attitude: a,
                    pathName: s,
                    person: {
                        type: l
                    },
                    noMedia: u,
                    tiles: [0, 1, 2, 4]
                }
            }
        };
        return logger.debug("send data: visitor to audience"),
        this.sendData({
            data: c
        })
    }
    removeVisitor(e) {
        const {removeType: t, userIDList: r, extraInfo: n=""} = e
          , o = {
            action_type: Actions.RemoveVisitor,
            removeVisitorAction: {
                removeVisitorEvent: t,
                userIDList: r,
                extraInfo: encodeURIComponent(n)
            }
        };
        return logger.debug("send data: remove visitor"),
        this.sendData({
            data: o
        })
    }
    getUserWithAvatar(e, t) {
        const r = {
            action_type: Actions.GetUserWithAvatar,
            getUserWithAvatarAction: {
                userType: e,
                roomID: t
            }
        };
        return logger.debug("send data: get user with avatar"),
        this.sendData({
            data: r
        }).then(n=>n.userWithAvatarList)
    }
    getNewUserState(e) {
        const i = {
            action_type: Actions.GetNewUserState,
            getNewUserStateAction: {
                userType: e
            }
        };
        return this.sendData({
            data: i,
            sampleRate: 0
        }).then(o => o)
    }
    setSyncPolicy({
        syncPolicy: e
    }) {
        const i = {
            action_type: Actions.SetSyncPolicy,
            setSyncPolicyAction: {
                syncPolicy: e
            }
        };
        return this.sendData({
            data: i
        })
    }
    joystick(e) {
        const {degree: t, level: r=1} = e
          , n = util.uuid();
        let o = -t + 90 + 360;
        o >= 360 && (o -= 360);
        const a = {
            action_type: Actions.Joystick,
            dir_action: {
                move_angle: o,
                speed_level: r
            },
            trace_id: n,
            user_id: this.room.options.userId,
            packet_id: n
        };
        return this.sendData({
            data: a,
            track: !1
        })
    }
}