import net from 'net';
import { EventEmitter } from 'events';
import logger from '../../utils/logger.js';
var PacketType;
(function (PacketType) {
    PacketType[PacketType["SERVERDATA_AUTH"] = 3] = "SERVERDATA_AUTH";
    PacketType[PacketType["SERVERDATA_AUTH_RESPONSE"] = 2] = "SERVERDATA_AUTH_RESPONSE";
    PacketType[PacketType["SERVERDATA_EXECCOMMAND"] = 2] = "SERVERDATA_EXECCOMMAND";
    PacketType[PacketType["SERVERDATA_RESPONSE_VALUE"] = 0] = "SERVERDATA_RESPONSE_VALUE";
})(PacketType || (PacketType = {}));
export var RconStatus;
(function (RconStatus) {
    RconStatus["DISCONNECTED"] = "disconnected";
    RconStatus["CONNECTING"] = "connecting";
    RconStatus["CONNECTED"] = "connected";
    RconStatus["AUTHENTICATED"] = "authenticated";
    RconStatus["ERROR"] = "error";
})(RconStatus || (RconStatus = {}));
export class RconManager extends EventEmitter {
    constructor() {
        super();
        this.socket = null;
        this.status = RconStatus.DISCONNECTED;
        this.config = null;
        this.requestId = 1;
        this.pendingRequests = new Map();
        this.buffer = Buffer.alloc(0);
    }
    async connect(config) {
        return new Promise((resolve, reject) => {
            if (this.status === RconStatus.CONNECTED || this.status === RconStatus.AUTHENTICATED) {
                return resolve();
            }
            this.config = config;
            this.status = RconStatus.CONNECTING;
            this.emit('statusChange', this.status);
            this.socket = new net.Socket();
            this.socket.setTimeout(config.timeout || 5000);
            this.socket.on('connect', () => {
                logger.info(`RCON连接成功: ${config.host}:${config.port}`);
                this.status = RconStatus.CONNECTED;
                this.emit('statusChange', this.status);
                this.authenticate(config.password).then(resolve).catch(reject);
            });
            this.socket.on('data', (data) => {
                this.handleData(data);
            });
            this.socket.on('error', (error) => {
                logger.error('RCON连接错误:', error);
                this.status = RconStatus.ERROR;
                this.emit('statusChange', this.status);
                this.emit('error', error);
                reject(error);
            });
            this.socket.on('close', () => {
                logger.info('RCON连接已关闭');
                this.status = RconStatus.DISCONNECTED;
                this.emit('statusChange', this.status);
                this.emit('disconnect');
                this.cleanup();
            });
            this.socket.on('timeout', () => {
                logger.error('RCON连接超时');
                this.status = RconStatus.ERROR;
                this.emit('statusChange', this.status);
                this.emit('error', new Error('连接超时'));
                this.disconnect();
                reject(new Error('连接超时'));
            });
            this.socket.connect(config.port, config.host);
        });
    }
    disconnect() {
        if (this.socket) {
            this.socket.destroy();
        }
        this.cleanup();
    }
    cleanup() {
        this.socket = null;
        this.status = RconStatus.DISCONNECTED;
        this.buffer = Buffer.alloc(0);
        for (const [id, request] of this.pendingRequests) {
            clearTimeout(request.timeout);
            request.reject(new Error('连接已断开'));
        }
        this.pendingRequests.clear();
    }
    async authenticate(password) {
        return new Promise((resolve, reject) => {
            const packet = this.createPacket(PacketType.SERVERDATA_AUTH, password);
            const requestId = packet.id;
            this.sendPacket(packet);
            const timeout = setTimeout(() => {
                this.pendingRequests.delete(requestId);
                reject(new Error('身份验证超时'));
            }, 5000);
            this.pendingRequests.set(requestId, {
                resolve: (response) => {
                    clearTimeout(timeout);
                    if (response.id === requestId) {
                        this.status = RconStatus.AUTHENTICATED;
                        this.emit('statusChange', this.status);
                        logger.info('RCON身份验证成功');
                        resolve();
                    }
                    else {
                        reject(new Error('身份验证失败'));
                    }
                },
                reject: (error) => {
                    clearTimeout(timeout);
                    reject(error);
                },
                timeout
            });
        });
    }
    async executeCommand(command) {
        return new Promise((resolve, reject) => {
            if (this.status !== RconStatus.AUTHENTICATED) {
                return reject(new Error('RCON未连接或未认证'));
            }
            const packet = this.createPacket(PacketType.SERVERDATA_EXECCOMMAND, command);
            const requestId = packet.id;
            this.sendPacket(packet);
            const timeout = setTimeout(() => {
                this.pendingRequests.delete(requestId);
                reject(new Error('命令执行超时'));
            }, 10000);
            this.pendingRequests.set(requestId, {
                resolve: (response) => {
                    clearTimeout(timeout);
                    resolve(response.body);
                },
                reject: (error) => {
                    clearTimeout(timeout);
                    reject(error);
                },
                timeout
            });
        });
    }
    createPacket(type, body) {
        const id = this.requestId++;
        return { id, type, body };
    }
    sendPacket(packet) {
        if (!this.socket) {
            throw new Error('Socket未连接');
        }
        const bodyBuffer = Buffer.from(packet.body, 'utf8');
        const length = 4 + 4 + bodyBuffer.length + 2;
        const buffer = Buffer.alloc(4 + length);
        let offset = 0;
        buffer.writeInt32LE(length, offset);
        offset += 4;
        buffer.writeInt32LE(packet.id, offset);
        offset += 4;
        buffer.writeInt32LE(packet.type, offset);
        offset += 4;
        bodyBuffer.copy(buffer, offset);
        offset += bodyBuffer.length;
        buffer.writeUInt8(0, offset);
        buffer.writeUInt8(0, offset + 1);
        this.socket.write(buffer);
    }
    handleData(data) {
        this.buffer = Buffer.concat([this.buffer, data]);
        while (this.buffer.length >= 4) {
            const length = this.buffer.readInt32LE(0);
            if (this.buffer.length < 4 + length) {
                break;
            }
            const packet = this.parsePacket(this.buffer.slice(4, 4 + length));
            this.buffer = this.buffer.slice(4 + length);
            this.handlePacket(packet);
        }
    }
    parsePacket(buffer) {
        const id = buffer.readInt32LE(0);
        const type = buffer.readInt32LE(4);
        const body = buffer.slice(8, buffer.length - 2).toString('utf8');
        return { id, type, body };
    }
    handlePacket(packet) {
        const request = this.pendingRequests.get(packet.id);
        if (request) {
            this.pendingRequests.delete(packet.id);
            if (packet.type === PacketType.SERVERDATA_AUTH_RESPONSE) {
                if (packet.id === -1) {
                    request.reject(new Error('身份验证失败：密码错误'));
                }
                else {
                    request.resolve(packet);
                }
            }
            else if (packet.type === PacketType.SERVERDATA_RESPONSE_VALUE) {
                request.resolve(packet);
            }
        }
        this.emit('packet', packet);
    }
    getStatus() {
        return this.status;
    }
    getConfig() {
        return this.config;
    }
    isConnected() {
        return this.status === RconStatus.AUTHENTICATED;
    }
}
export default RconManager;
