// sshmanager.cpp
#include "sshmanager.h"

SSHManager* SSHManager::m_instance = nullptr;
SSHManager* SSHManager::instance() {
    if (!m_instance) {
        m_instance = new SSHManager();
    }
    return m_instance;
}

SSHManager::SSHManager(QObject *parent) : QObject(parent) {
    m_session = nullptr;
    m_channel = nullptr;
    m_socket = nullptr;
    m_notifier = nullptr;
    m_sock = -1;  // 初始化为无效值

}
SSHManager::~SSHManager() {
    // 清理资源代码...
    // 关闭会话、释放socket等

}
//连接
void SSHManager::connectAndStartShell(const QString &ip, const QString &port, const QString &username, const QString &password)
{
    emit statusMessage(u8"开始连接服务器...");

    Myip = ip;
    Myport = port;
    Myuser = username;
    Mypass = password;

    // 初始化 LibSSH2
    if (libssh2_init(0) != 0) {
        connectionFailed(u8"初始化SSH失败！");
        return;
    }

    // 创建 TCP 套接字
    m_socket = new QTcpSocket(this);
    m_socket->setProxy(QNetworkProxy::NoProxy);

    // 创建一个定时器用于设置连接超时
    QTimer *timer = new QTimer(this);
    timer->setSingleShot(true); // 只触发一次
    QObject::connect(timer, &QTimer::timeout, [this]() {
        if (m_socket->state() != QAbstractSocket::ConnectedState) {
            m_socket->abort(); // 断开连接
            connectionFailed(u8"连接超时！请检查网络或稍后重试。");
        }
    });

    // 连接信号
    QObject::connect(m_socket, &QTcpSocket::connected, [this, timer]() {
        timer->stop(); // 连接成功，停止定时器
        handleConnected();
    });
    QObject::connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::errorOccurred),
                     [this, timer](QAbstractSocket::SocketError) {
                         timer->stop(); // 连接出错，停止定时器
                         connectionFailed(u8"连接失败！检查IP和端口是否正确！");
                     });

    // 开始非阻塞连接
    m_socket->connectToHost(ip, port.toInt());

    // 启动定时器，设置超时时间为 5 秒
    timer->start(5000);
}

void SSHManager::handleConnected()
{
    m_sock = m_socket->socketDescriptor();

    // 创建会话并设置为非阻塞
    m_session = libssh2_session_init();
    libssh2_session_set_blocking(m_session, 0);

    // 开始会话建立
    m_connectionStep = CONNECTION_STARTUP;
    trySessionStartup();
}

void SSHManager::trySessionStartup()
{
    int rc = libssh2_session_startup(m_session, m_sock);

    if (rc == LIBSSH2_ERROR_EAGAIN) {
        setupSocketNotifier();
        return;
    }

    if (rc != 0) {
        connectionFailed(u8"启动会话失败！");
        cleanup();
        return;
    }

    // 会话建立成功，开始认证
    m_connectionStep = AUTHENTICATION;
    tryAuthentication();
}

void SSHManager::tryAuthentication()
{
    int rc = libssh2_userauth_password(m_session, Myuser.toUtf8().constData(), Mypass.toUtf8().constData());

    if (rc == LIBSSH2_ERROR_EAGAIN) {
        setupSocketNotifier();
        return;
    }

    if (rc != 0) {
        connectionFailed(u8"账号或密码错误！请检查！");
        cleanup();
        return;
    }

    // 认证成功，创建通道
    m_connectionStep = CHANNEL_CREATION;
    tryChannelCreation();
}

void SSHManager::tryChannelCreation()
{
    m_channel = libssh2_channel_open_session(m_session);

    if (!m_channel) {
        int rc = libssh2_session_last_error(m_session, nullptr, nullptr, 0);
        if (rc == LIBSSH2_ERROR_EAGAIN) {
            setupSocketNotifier();
            return;
        }
        emit shellOutput(u8"\033[31mERROR: 无法创建终端通道\033[0m\r\n");
        cleanup();
        return;
    }

    // 通道创建成功，设置参数
    libssh2_channel_handle_extended_data(m_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE);
    m_connectionStep = PTY_SETUP;
    tryPtySetup();
}

void SSHManager::tryPtySetup()
{
    int rc = libssh2_channel_request_pty(m_channel, "xterm-256color");

    if (rc == LIBSSH2_ERROR_EAGAIN) {
        setupSocketNotifier();
        return;
    }

    if (rc != 0) {
        emit shellOutput(u8"\033[31mERROR: 无法分配伪终端\033[0m\r\n");
        cleanup();
        return;
    }

    // PTY设置成功，启动shell
    m_connectionStep = SHELL_START;
    tryShellStart();
}

void SSHManager::tryShellStart()
{
    int rc = libssh2_channel_shell(m_channel);

    if (rc == LIBSSH2_ERROR_EAGAIN) {
        setupSocketNotifier();
        return;
    }

    if (rc != 0) {
        emit shellOutput(u8"\033[31mERROR: 无法启动Shell\033[0m\r\n");
        cleanup();
        return;
    }

    // Shell启动成功，设置数据监听
    m_notifier = new QSocketNotifier(m_sock, QSocketNotifier::Read, this);
    connect(m_notifier, &QSocketNotifier::activated, this, &SSHManager::readShellOutput);

    emit shellOutput(u8"\033[32m已连接到服务器，开始交互会话...\033[0m\r\n");
    connectionSuccess();
}

void SSHManager::setupSocketNotifier()
{
    // 先销毁旧的通知器
    if (m_notifier) {
        m_notifier->setEnabled(false);  // 立即禁用
        m_notifier->deleteLater();      // 安全删除
        m_notifier = nullptr;           // 重置指针
    }


    int directions = libssh2_session_block_directions(m_session);

    // 优先处理写操作
    QSocketNotifier::Type type = QSocketNotifier::Read;
    if (directions & LIBSSH2_SESSION_BLOCK_OUTBOUND || !m_writeBuffer.isEmpty()) {
        type = QSocketNotifier::Write;
    } else if (directions & LIBSSH2_SESSION_BLOCK_INBOUND) {
        type = QSocketNotifier::Read;
    }

    m_notifier = new QSocketNotifier(m_sock, type, this);
    connect(m_notifier, &QSocketNotifier::activated, this, [this]() {
        // 处理读写事件
        if (m_notifier->type() == QSocketNotifier::Write) {
            trySendData();
        }
        handleNextStep();
    });
}

void SSHManager::handleNextStep()
{
    switch (m_connectionStep) {
    case CONNECTION_STARTUP:  trySessionStartup(); break;
    case AUTHENTICATION:       tryAuthentication(); break;
    case CHANNEL_CREATION:     tryChannelCreation(); break;
    case PTY_SETUP:            tryPtySetup(); break;
    case SHELL_START:          tryShellStart(); break;
    default: break;
    }
}

void SSHManager::readShellOutput()
{
    char buffer[4096];
    while (true) {
        int nbytes = libssh2_channel_read_ex(m_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_DEFAULT,
                                             buffer, sizeof(buffer));
        if (nbytes > 0) {
            emit shellOutput(QByteArray(buffer, nbytes));
        }
        else if (nbytes == LIBSSH2_ERROR_EAGAIN) {
            break;
        }
        else {
            if (nbytes != LIBSSH2_ERROR_CHANNEL_CLOSED) {
                emit shellOutput(u8"\033[31m连接异常断开\033[0m\r\n");
            }
            cleanup();
            break;
        }
    }
}

void SSHManager::cleanup()
{
    if (m_channel) {
        libssh2_channel_free(m_channel);
        m_channel = nullptr;
    }
    if (m_session) {
        libssh2_session_free(m_session);
        m_session = nullptr;
    }
    if (m_socket) {
        m_socket->disconnectFromHost();
        m_socket->deleteLater();
        m_socket = nullptr;
    }
    libssh2_exit();
}

// 在实现文件 SSHManager.cpp 中添加以下实现
void SSHManager::sendInput(const QString &input)
{
    if (!m_channel || !m_session) {
        emit shellOutput(u8"\033[31m错误：连接未建立\033[0m\r\n");
        return;
    }

    // 将输入转换为UTF-8并追加换行符
    QByteArray data = input.toUtf8() + '\n';

    // 添加到发送缓冲区
    m_writeBuffer.append(data);

    // 立即尝试发送
    trySendData();
}

void SSHManager::trySendData()
{
    while (!m_writeBuffer.isEmpty()) {
        // 非阻塞模式发送
        ssize_t n = libssh2_channel_write_ex(
            m_channel,
            LIBSSH2_CHANNEL_EXTENDED_DATA_DEFAULT,
            m_writeBuffer.constData() + m_writeOffset,
            m_writeBuffer.size() - m_writeOffset
            );

        if (n > 0) {
            // 更新发送偏移
            m_writeOffset += n;

            // 如果全部发送完成
            if (m_writeOffset >= m_writeBuffer.size()) {
                m_writeBuffer.clear();
                m_writeOffset = 0;
                return;
            }
        }
        else if (n == LIBSSH2_ERROR_EAGAIN) {
            // 设置写监控
            setupSocketNotifier();
            return;
        }
        else {
            // 处理发送错误
            emit shellOutput(u8"\033[31m发送失败，连接可能已断开\033[0m\r\n");
            cleanup();
            return;
        }
    }
}

//判断是否连接
bool SSHManager::isConnected() {
    if (!m_session) {
        connectionFailed(u8"SSH连接已被断开,可能是服务器设置了响应时间");
        return false;
    }
    int rc = libssh2_session_last_error(m_session, nullptr, nullptr, 0);
    return rc == 0;
}

//重连
void SSHManager::reconnect() {
    // 先清理现有连接资源
    if (m_session) {
        libssh2_session_disconnect(m_session, "Reconnecting");
        libssh2_session_free(m_session);
        m_session = nullptr;
    }
    if (m_socket) {
        m_socket->close();
        m_socket->deleteLater();
        m_socket = nullptr;
    }
    libssh2_exit();

    // 重新连接
    connectAndStartShell(Myip,Myport,Myuser,Mypass);
    statusMessage(u8"重新连接服务器成功");
}

void SSHManager::disconnectFromServer() {
    // 清理交互式通道
    if (m_channel) {
        libssh2_channel_close(m_channel);
        libssh2_channel_free(m_channel);
        m_channel = nullptr;
    }

    // 清理终端监听器
    if (m_notifier) {
        m_notifier->setEnabled(false);
        delete m_notifier;
        m_notifier = nullptr;
    }

    // 清理SSH会话
    if (m_session) {
        libssh2_session_disconnect(m_session, "User initiated disconnect");
        libssh2_session_free(m_session);
        m_session = nullptr;
    }

    // 清理套接字
    if (m_socket) {
        if (m_socket->state() == QAbstractSocket::ConnectedState) {
            m_socket->disconnectFromHost();
            if (!m_socket->waitForDisconnected(1000)) {
                m_socket->abort();
            }
        }
        m_socket->deleteLater();
        m_socket = nullptr;
    }

    // 通知界面连接已断开
    emit disconnected();
    emit statusMessage(u8"已断开与服务器的连接");
}

