/*******************************************************************************
 * Copyright (c) 2024-2025 R3944Realms. All rights reserved.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 *     http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.r3944realms.dg_lab.websocket;

import com.r3944realms.dg_lab.api.operation.ServerOperation;
import com.r3944realms.dg_lab.websocket.handler.server.DefaultServerOperation;
import com.r3944realms.dg_lab.websocket.handler.server.ServerDLPBHandler;
import com.r3944realms.dg_lab.websocket.handler.server.ServerDLPBHandlerContextWrapper;
import com.r3944realms.dg_lab.api.websocket.message.Message;
import com.r3944realms.dg_lab.api.websocket.message.PowerBoxMessage;
import com.r3944realms.dg_lab.api.websocket.message.role.WebSocketServerRole;
import com.r3944realms.dg_lab.websocket.sharedData.ServerPowerBoxSharedData;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.Timer;
import java.util.concurrent.CompletableFuture;

/**
 * 处理PowerBox的Websocket消息的服务器实现
 */
public class PowerBoxWSServer extends AbstractWebSocketServer {
    /**
     * The Shared data.
     */
    protected final ServerPowerBoxSharedData SharedData;
    /**
     * The Role.
     */
    protected final WebSocketServerRole role;
    /**
     * The Operation.
     */
    protected final ServerOperation operation;
    private final ServerDLPBHandlerContextWrapper contextWrapper;

    /**
     * Instantiates a new Power box ws server.
     *
     * @param sharedData the shared data
     * @param role       the role
     * @param operation  the operation
     */
    public PowerBoxWSServer(ServerPowerBoxSharedData sharedData, WebSocketServerRole role, ServerOperation operation) {
        this.SharedData = sharedData;
        this.role = role;
        this.operation = operation;
        contextWrapper = new ServerDLPBHandlerContextWrapper(
                sharedData,
                role,
                operation
        );
    }

    /**
     * Instantiates a new Power box ws server.
     *
     * @param sharedData the shared data
     * @param role       the role
     * @param operation  the operation
     * @param port       the port
     */
    public PowerBoxWSServer(ServerPowerBoxSharedData sharedData, WebSocketServerRole role, ServerOperation operation, int port) {
        super(port);
        this.SharedData = sharedData;
        this.role = role;
        this.operation = operation;
        contextWrapper = new ServerDLPBHandlerContextWrapper(
                sharedData,
                role,
                operation
        );
    }

    /**
     * Instantiates a new Power box ws server.
     *
     * @param sharedData the shared data
     * @param role       the role
     */
    public PowerBoxWSServer(ServerPowerBoxSharedData sharedData, WebSocketServerRole role) {
       this(sharedData, role, new DefaultServerOperation());
    }

    /**
     * Instantiates a new Power box ws server.
     *
     * @param sharedData the shared data
     * @param role       the role
     * @param port       the port
     */
    public PowerBoxWSServer(ServerPowerBoxSharedData sharedData, WebSocketServerRole role, int port) {
        this(sharedData, role, new DefaultServerOperation(), port);
    }

    @Override
    protected void MessagePipeLineHandler(ChannelPipeline pipeline) {
        pipeline.addLast(new ServerDLPBHandler(contextWrapper));
    }

    @Override
    protected void starting() {
        operation.ServerStartingHandler();
    }

    @Override
    protected void startingError() {
        operation.ServerStartingErrorHandler();
    }

    @Override
    protected void started() {
        operation.ServerStartedHandler();
    }

    @Override
    protected void stopping() {
        operation.ServerStoppingHandler();
    }

    @Override
    protected void stoppingError() {
        operation.ServerStoppingErrorHandler();
    }

    @Override
    protected void stopped() {
        operation.ServerStoppedHandler();
    }

    @Override
    public void send(String connectId, Message message) {
        if(message instanceof PowerBoxMessage PBMessage) {
            ChannelHandlerContext context = SharedData.connections.get(connectId);//获取连接连接的Context
            if(context != null) {
                String targetId = SharedData.relations.get(connectId);
                if(targetId.isEmpty()) { //该上下文为客户端
                    context.writeAndFlush(new TextWebSocketFrame(PBMessage.getMsgJson()));//发送给客户端
                    ChannelHandlerContext appContext = SharedData.connections.get(targetId);
                    appContext.writeAndFlush(new TextWebSocketFrame(PBMessage.getDataJson()));//发送给APP端
                } else if(SharedData.relations.containsValue(targetId)){  // 绑定状态的APP端
                    //仅对APP发信息
                    context.writeAndFlush(new TextWebSocketFrame(PBMessage.getDataJson()));

                } else { // 未绑定状态（不可发送消息）
                    logger.error("Can't send Msg to no relationship obj.");
                }
            } else {
                logger.error("Find that Target is invalid.");
            }
        } else {
            logger.error("Message is not a PowerBoxMessage");
        }
    }

    /**
     * Gets shared data.
     *
     * @return the shared data
     */
    public ServerPowerBoxSharedData getSharedData() {
        return SharedData;
    }

    @Override
    protected CompletableFuture<Void> stop0() {
        return CompletableFuture.runAsync(
                () -> {
                    Timer heartTimer = getSharedData().heartTimer;
                    if (heartTimer != null) {
                        heartTimer.cancel();
                    }
                }
        );
    }

    /**
     * 必要要设置{@link ServerPowerBoxSharedData sharedData}和{@link WebSocketServerRole role}正确值
     */
    public static final class Builder {
        /**
         * The Shared data.
         */
        ServerPowerBoxSharedData sharedData;
        /**
         * The Role.
         */
        WebSocketServerRole role;
        /**
         * The Port.
         */
        int port;
        /**
         * The Operation.
         */
        ServerOperation operation;
        private Builder() {
            role = null;
            sharedData = null;
            operation = null;
            port = -1;
        }

        /**
         * Gets builder.
         *
         * @return the builder
         */
        public static Builder getBuilder() {
            return new Builder();
        }

        /**
         * Shared data builder.
         *
         * @param sharedData the shared data
         * @return the builder
         */
        public Builder sharedData(ServerPowerBoxSharedData sharedData) {
            this.sharedData = sharedData;
            return this;
        }

        /**
         * Port builder.
         *
         * @param port the port
         * @return the builder
         */
        public Builder port(int port) {
            this.port = port;
            return this;
        }

        /**
         * Operation builder.
         *
         * @param operation the operation
         * @return the builder
         */
        public Builder operation(ServerOperation operation) {
            this.operation = operation;
            return this;
        }

        /**
         * Role builder.
         *
         * @param role the role
         * @return the builder
         */
        public Builder role(WebSocketServerRole role) {
            this.role = role;
            return this;
        }

        /**
         * Build power box ws server.
         *
         * @return the power box ws server
         */
        public PowerBoxWSServer build() {
            if (sharedData == null || role == null)
                throw new UnsupportedOperationException("Lost key value, failed to build");
            return (operation == null) ?  (port == -1) ?
                    new PowerBoxWSServer(sharedData, role) :
                    new PowerBoxWSServer(sharedData, role, port)
            : (port == -1) ?
                    new PowerBoxWSServer(sharedData, role, operation) :
                    new PowerBoxWSServer(sharedData, role, operation, port);
        }
    }
}
