/*******************************************************************************
 * 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.ClientOperation;
import com.r3944realms.dg_lab.websocket.handler.client.ClientDLPBHandler;
import com.r3944realms.dg_lab.websocket.handler.client.ClientDLPBHandlerContextWrapper;
import com.r3944realms.dg_lab.websocket.handler.client.DefaultClientOperation;
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.WebSocketClientRole;
import com.r3944realms.dg_lab.websocket.sharedData.ClientPowerBoxSharedData;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

/**
 * 处理PowerBox的Websocket消息的客户端实现
 */
public class PowerBoxWSClient extends AbstractWebSocketClient {
    /**
     * The Shared data.
     */
    protected final ClientPowerBoxSharedData sharedData;
    /**
     * The Role.
     */
    protected final WebSocketClientRole role;
    /**
     * The Operation.
     */
    protected final ClientOperation operation;
    /**
     * The Use role msg mode.
     */
    protected final boolean useRoleMsgMode;
    private final ClientDLPBHandlerContextWrapper contextWrapper;

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData the shared data
     * @param role       the role
     * @param operation  the operation
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, ClientOperation operation) {
        super();
        this.useRoleMsgMode = false;
        this.sharedData = sharedData;
        this.operation = operation;
        this.role = role;
        sharedData.address = this.Address;
        sharedData.port = this.Port;
        contextWrapper = new ClientDLPBHandlerContextWrapper(sharedData, role, operation, false);
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData the shared data
     * @param role       the role
     * @param operation  the operation
     * @param address    the address
     * @param port       the port
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, ClientOperation operation, String address, int port) {
        super(address, port);
        this.useRoleMsgMode = false;
        this.sharedData = sharedData;
        this.operation = operation;
        this.role = role;
        sharedData.address = this.Address;
        sharedData.port = this.Port;
        contextWrapper = new ClientDLPBHandlerContextWrapper(sharedData, role, operation, false);
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData the shared data
     * @param role       the role
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role) {
        this(sharedData, role, new DefaultClientOperation());
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData the shared data
     * @param role       the role
     * @param address    the address
     * @param port       the port
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, String address, int port) {
        this(sharedData, role, new DefaultClientOperation(), address, port);
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData     the shared data
     * @param role           the role
     * @param operation      the operation
     * @param useRoleMsgMode the use role msg mode
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, ClientOperation operation, boolean useRoleMsgMode) {
        super();
        this.useRoleMsgMode = useRoleMsgMode;
        this.sharedData = sharedData;
        this.operation = operation;
        this.role = role;
        sharedData.address = this.Address;
        sharedData.port = this.Port;
        contextWrapper = new ClientDLPBHandlerContextWrapper(sharedData, role, operation, useRoleMsgMode);
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData     the shared data
     * @param role           the role
     * @param operation      the operation
     * @param useRoleMsgMode the use role msg mode
     * @param address        the address
     * @param port           the port
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, ClientOperation operation, boolean useRoleMsgMode,String address, int port) {
        super(address, port);
        this.useRoleMsgMode = useRoleMsgMode;
        this.sharedData = sharedData;
        this.operation = operation;
        this.role = role;
        sharedData.address = this.Address;
        sharedData.port = this.Port;
        contextWrapper = new ClientDLPBHandlerContextWrapper(sharedData, role, operation, useRoleMsgMode);
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData     the shared data
     * @param role           the role
     * @param useRoleMsgMode the use role msg mode
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, boolean useRoleMsgMode) {
        this(sharedData, role, new DefaultClientOperation(), useRoleMsgMode);
    }

    /**
     * Instantiates a new Power box ws client.
     *
     * @param sharedData     the shared data
     * @param role           the role
     * @param useRoleMsgMode the use role msg mode
     * @param address        the address
     * @param port           the port
     */
    public PowerBoxWSClient(ClientPowerBoxSharedData sharedData, WebSocketClientRole role, boolean useRoleMsgMode, String address, int port) {
        this(sharedData, role, new DefaultClientOperation(), useRoleMsgMode, address, port);
    }
    @Override
    protected void MessagePipeLineHandler(ChannelPipeline pipeline) {
        pipeline.addLast(new ClientDLPBHandler(contextWrapper));
    }

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

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

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

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

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

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

    @Override
    public void send(Message message) {
        if(message instanceof PowerBoxMessage PBMessage) {
            this.ClientChannel.writeAndFlush(new TextWebSocketFrame(PBMessage.getMsgJson()));
        } else {
            logger.error("Message is not a PowerBoxMessage");
        }
    }

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

    /**
     * 必要要设置{@link ClientPowerBoxSharedData sharedData}和{@link WebSocketClientRole role}正确值
     */
    public final static class Builder {
        /**
         * The Shared data.
         */
        ClientPowerBoxSharedData sharedData;
        /**
         * The Role.
         */
        WebSocketClientRole role;
        /**
         * The Operation.
         */
        ClientOperation operation;
        /**
         * The Address.
         */
        String address;
        /**
         * The Port.
         */
        int port;
        /**
         * The Use role msg mode.
         */
        boolean useRoleMsgMode;
        private Builder() {
            role = null;
            sharedData = null;
            operation = null;
            address = null;
            port = -1;
            useRoleMsgMode = false;
        }

        /**
         * 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(ClientPowerBoxSharedData sharedData) {
            this.sharedData = sharedData;
            return this;
        }

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

        /**
         * Address and port builder.
         *
         * @param address the address
         * @param port    the port
         * @return the builder
         */
        public Builder addressAndPort(String address, int port) {
            this.address = address;
            this.port = port;
            return this;
        }

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

        /**
         * Address builder.
         *
         * @param address the address
         * @return the builder
         */
        public Builder address(String address) {
            this.address = address;
            return this;
        }

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

        /**
         * Use role msg mode builder.
         *
         * @param useRoleMsgMode the use role msg mode
         * @return the builder
         */
        public Builder useRoleMsgMode(boolean useRoleMsgMode) {
            this.useRoleMsgMode = useRoleMsgMode;
            return this;
        }

        /**
         * Build power box ws client.
         *
         * @return the power box ws client
         */
        public PowerBoxWSClient build() {
            if (sharedData == null || role == null)
                throw new UnsupportedOperationException("Lost key value, failed to build");
            boolean isAddressAndPortDefaultValue = port == -1 || address == null;//使用默认地址与端口
            boolean isOperationDefaultValue = this.operation == null;//使用默认操作
            return (useRoleMsgMode) ?
                    isOperationDefaultValue ?
                        isAddressAndPortDefaultValue ?
                            new PowerBoxWSClient(sharedData, role, true) :
                            new PowerBoxWSClient(sharedData, role,true, address, port)
                    :
                        isAddressAndPortDefaultValue ?
                            new PowerBoxWSClient(sharedData, role, operation, true) :
                            new PowerBoxWSClient(sharedData, role, operation, true, address, port)
                : isOperationDefaultValue ?
                        isAddressAndPortDefaultValue ?
                            new PowerBoxWSClient(sharedData, role) :
                            new PowerBoxWSClient(sharedData, role, address, port)
                    :
                        isAddressAndPortDefaultValue ?
                            new PowerBoxWSClient(sharedData, role, operation) :
                            new PowerBoxWSClient(sharedData, role, operation, address, port);
        }
    }
}
