#include "SDLWindow.h"

#include <iostream>

#include <irrKlang.h>

// include console I/O methods (conio.h for windows, our wrapper in linux)
#if defined(WIN32)
#include <conio.h>
#else
#include "../common/conio.h"
#endif


#include "serial/serial.h"


constexpr char kWindowClassName[] = "Playsound";
constexpr char kWindowName[] = "Playsound";

SDLWindow::SDLWindow()
{
    // 创建窗口
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = StaticWindowProcedure;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = kWindowClassName;
    RegisterClass(&wc);

    hWnd = CreateWindow(wc.lpszClassName, kWindowName, 0, CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, wc.hInstance, (LPVOID)this);
}

SDLWindow::~SDLWindow()
{
    // 移除托盘图标
    Shell_NotifyIcon(NIM_DELETE, &trayIconData);
}

int32_t SDLWindow::Run()
{
    // 创建托盘图标
    CreateTrayIcon();

    // 初始化SDL音频设备
    if (SDL_Init(SDL_INIT_AUDIO) < 0) {
        std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl;
        return -1;
    }

    SDL_AtomicSet(&Quit, 0);

    SDL_zero(audioSpec);
    audioSpec.freq = 44100;
    audioSpec.format = AUDIO_S16SYS;
    audioSpec.channels = 2;
    audioSpec.samples = 4096;
    audioSpec.callback = AudioCallback;

    audioDeviceID = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
    if (audioDeviceID == 0) {
        std::cerr << "Failed to open audio device: " << SDL_GetError() << std::endl;
        return -1;
    }

    // 创建串口监听线程
    HANDLE hSerialListenerThread = CreateThread(NULL, 0, SerialListenerThread, this, 0, NULL);

    // 主消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 等待串口监听线程结束
    WaitForSingleObject(hSerialListenerThread, INFINITE);
    CloseHandle(hSerialListenerThread);

    // 停止音频设备
    SDL_PauseAudioDevice(audioDeviceID, 1);
    SDL_CloseAudioDevice(audioDeviceID);
    SDL_Quit();
    return 0;
}

void SDLWindow::CreateTrayIcon()
{
    ZeroMemory(&trayIconData, sizeof(NOTIFYICONDATA));
    trayIconData.cbSize = sizeof(NOTIFYICONDATA);
    trayIconData.hWnd = hWnd;
    trayIconData.uID = TRAY_ICON_ID;
    trayIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    trayIconData.uCallbackMessage = WM_TRAYICON;
    trayIconData.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_APPLICATION));
    strcpy_s(trayIconData.szTip, sizeof(trayIconData.szTip), kWindowName);

    Shell_NotifyIcon(NIM_ADD, &trayIconData);
}

void SDLWindow::QuitApplication()
{
    // 在这里添加退出逻辑
    SDL_AtomicSet(&Quit, 1);

    // 终止应用程序消息循环
    PostQuitMessage(0);
}

LRESULT SDLWindow::WindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_TRAYICON && wParam == TRAY_ICON_ID) {
        if (lParam == WM_RBUTTONDOWN) {
            // 创建右键退出菜单
            HMENU hMenu = CreatePopupMenu();
            AppendMenu(hMenu, MF_STRING, 1, "Exit");

            // 获取鼠标位置
            POINT pt;
            GetCursorPos(&pt);

            // 显示右键退出菜单
            SetForegroundWindow(hWnd);
            TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL);
            
            // 销毁菜单
            DestroyMenu(hMenu);
        }
    } else if (uMsg == WM_COMMAND && LOWORD(wParam) == 1) {
        // 退出菜单被点击
        QuitApplication();
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK SDLWindow::StaticWindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    SDLWindow* pWindow = nullptr;

    if (uMsg == WM_NCCREATE) {
        CREATESTRUCT* pCreateStruct = (CREATESTRUCT*)lParam;
        pWindow = (SDLWindow*)pCreateStruct->lpCreateParams;

        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWindow);
    } else {
        pWindow = (SDLWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    }

    if (pWindow) {
        return pWindow->WindowProcedure(hWnd, uMsg, wParam, lParam);
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

DWORD WINAPI SDLWindow::SerialListenerThread(LPVOID lpParam) {
    SDLWindow* pWindow = (SDLWindow*)lpParam;

    TCHAR path[MAX_PATH] = { 0 };
    GetModuleFileName(NULL, path, sizeof(path));
    std::string exeDir = path;
    std::size_t pos = exeDir.find_last_of("\\/");
    if (pos != std::string::npos) {
        exeDir = exeDir.substr(0, pos);
    }

    const std::string configPath = exeDir + "\\playsound.ini";
    const TCHAR* iniFile = configPath.c_str();
    TCHAR section[] = TEXT("Settings");

    TCHAR port[256];
    DWORD code = GetPrivateProfileString(section, TEXT("port"), TEXT(""), port, sizeof(port), iniFile);
    DWORD errorCode = GetLastError();
    int baudrate = GetPrivateProfileInt(section, TEXT("baudrate"), 9600, iniFile);
    uint32_t timeout = GetPrivateProfileInt(section, TEXT("timeout"), 1000, iniFile);

    irrklang::ISoundEngine* soundEngine = irrklang::createIrrKlangDevice();
    if (nullptr == soundEngine) {
        return -1;
    }

    // 此处添加串口监听线程代码
    serial::Serial serialPort(port, baudrate, serial::Timeout::simpleTimeout(timeout));
    if (!serialPort.isOpen()) {
        return -1;
    }

    constexpr int32_t bufferSize = 1024;
    while (0 == SDL_AtomicGet(&pWindow->Quit)) {
        std::string result = serialPort.read(bufferSize);
        if (result.empty()) {
            continue;
        }

        // 此处添加串口数据处理代码
        
        //soundEngine->play2D()
        const std::string mediaPath = exeDir + "\\media\\getout.ogg";
        soundEngine->play2D(mediaPath.c_str());
    }

    soundEngine->drop();

    return 0;
}

void SDLWindow::AudioCallback(void* userdata, Uint8* stream, int len)
{
    // 此处添加音频处理代码
}