/*
 * Copyright (C) 2016-2022 ActionTech.
 * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
 */

package com.actiontech.dble.net.mysql;

import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.mysql.BufferUtil;
import com.actiontech.dble.backend.mysql.CharsetUtil;
import com.actiontech.dble.backend.mysql.MySQLMessage;
import com.actiontech.dble.config.Capabilities;
import com.actiontech.dble.net.connection.AbstractConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;

public class ChangeUserPacket extends MySQLPacket {
    private static final Logger LOGGER = LoggerFactory.getLogger(ChangeUserPacket.class);

    public static final byte STATUS = (byte) 0x11;

    private long clientFlags;
    private int charsetIndex;
    private String user;
    private byte[] password;
    private String database;
    private String authPlugin = "mysql_native_password";
    private String tenant = "";

    public ChangeUserPacket(long clientFlags) {
        this.clientFlags = clientFlags;
    }

    public ChangeUserPacket(String user) {
        this.user = user;
    }

    public void read(byte[] data) {
        MySQLMessage mm = new MySQLMessage(data);
        packetLength = mm.readUB3();
        packetId = mm.read();
        mm.position(5);
        user = mm.readStringWithNull(); //user name end by a [00]
        // it must be Capabilities.CLIENT_SECURE_CONNECTION
        password = mm.readBytesWithLength();
        database = mm.readStringWithNull();
        if (database != null && DbleServer.getInstance().getSystemVariables().isLowerCaseTableNames()) {
            database = database.toLowerCase();
        }
        if (mm.hasRemaining()) {
            charsetIndex = mm.readUB2();
            if ((clientFlags & Capabilities.CLIENT_PLUGIN_AUTH) != 0) {
                authPlugin = mm.readStringWithNull();
            }
            if ((clientFlags & Capabilities.CLIENT_CONNECT_ATTRS) != 0) {
                long attrLength = mm.readLength();
                while (attrLength > 0) {
                    long start = mm.position();
                    String charsetName = CharsetUtil.getJavaCharset(charsetIndex);
                    try {
                        String key = mm.readStringWithLength(charsetName);
                        String value = mm.readStringWithLength(charsetName);
                        if (key.equals("tenant")) {
                            tenant = value;
                        }
                    } catch (Exception e) {
                        LOGGER.warn("read attribute filed", e);
                    }
                    attrLength -= (mm.position() - start);
                }
            }
        }
    }

    @Override
    public void bufferWrite(AbstractConnection c) {
        ByteBuffer buffer = c.allocate();
        BufferUtil.writeUB3(buffer, calcPacketSize());
        buffer.put(packetId);
        buffer.put(STATUS);
        if (user != null) {
            byte[] userData = user.getBytes();
            buffer = c.checkWriteBuffer(buffer, userData.length + 1, true);
            BufferUtil.writeWithNull(buffer, userData);
        } else {
            buffer = c.checkWriteBuffer(buffer, 1, true);
            buffer.put((byte) 0x0);
        }
        if (password != null) {
            buffer = c.checkWriteBuffer(buffer, BufferUtil.getLength(password), true);
            BufferUtil.writeWithLength(buffer, password);
        } else {
            buffer = c.checkWriteBuffer(buffer, 1, true);
            buffer.put((byte) 0x0);
        }
        if (database != null) {
            byte[] databaseData = database.getBytes();
            buffer = c.checkWriteBuffer(buffer, databaseData.length + 1, true);
            BufferUtil.writeWithNull(buffer, database.getBytes());
        } else {
            buffer = c.checkWriteBuffer(buffer, 1, true);
            buffer.put((byte) 0x0);
        }
        BufferUtil.writeUB2(buffer, charsetIndex);
        //        if ((clientFlags & Capabilities.CLIENT_PLUGIN_AUTH) != 0) {
        buffer = c.checkWriteBuffer(buffer, authPlugin.getBytes().length + 1, true);
        BufferUtil.writeWithNull(buffer, authPlugin.getBytes());
        //        }
        c.getService().writeDirectly(buffer, getLastWriteFlag());
    }

    @Override
    public int calcPacketSize() {
        int size = 1;
        size += (user == null) ? 1 : user.length() + 1;
        size += (password == null) ? 1 : BufferUtil.getLength(password);
        size += (database == null) ? 1 : database.length() + 1;
        size += 2;
        size += (authPlugin == null) ? 1 : authPlugin.length() + 1;
        return size;
    }

    @Override
    protected String getPacketInfo() {
        return "MySQL ChangeUser Packet";
    }

    public int getCharsetIndex() {
        return charsetIndex;
    }

    public void setCharsetIndex(int charsetIndex) {
        this.charsetIndex = charsetIndex;
    }

    public String getUser() {
        return user;
    }

    public void setPassword(byte[] password) {
        this.password = password;
    }

    public byte[] getPassword() {
        return password;
    }

    public String getDatabase() {
        return database;
    }

    public String getAuthPlugin() {
        return authPlugin;
    }

    public String getTenant() {
        return tenant;
    }

    @Override
    public boolean isEndOfQuery() {
        return false;
    }
}
