#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <string>
#include <vector>
#include <stdint.h>
#include "../include/hwscapture.h"

// Demo-only AI frame copy. It is intentionally independent from SDK internals.
// The SDK frame memory is only valid inside the callback, so AI input must copy it.
struct AiCapturedFrame
{
    int slot = 0;
    int width = 0;
    int height = 0;
    HWS_PIXEL_FORMAT pixelFormat = HWS_PIXFMT_UNKNOWN;
    int stride0 = 0;
    int stride1 = 0;
    long long timestamp100ns = 0;
    long long frameIndex = 0;
    std::vector<unsigned char> plane0;
    std::vector<unsigned char> plane1;
};

struct AiCapturedAudioChunk
{
    int audioSource = 0;
    int sampleRate = 16000;
    int channels = 1;
    int bitsPerSample = 16;
    int sampleCount = 0;
    long long timestamp100ns = 0;
    long long chunkIndex = 0;
    std::string srcLangUtf8 = "auto";
    std::string dstLangUtf8 = "en";
    std::vector<unsigned char> pcm16;
};

struct AiDetection
{
    int classId = -1;
    std::string labelUtf8;
    double confidence = 0.0;
    double x = 0.0;
    double y = 0.0;
    double w = 0.0;
    double h = 0.0;
};

struct AiEvent
{
    std::string eventIdUtf8;
    std::string typeUtf8;
    std::string levelUtf8;
    std::string labelUtf8;
    std::string messageUtf8;
    int prevCount = -1;
    int currentCount = -1;
};

struct AiDemoResult
{
    // Result type follows the unified AI event stream. Examples:
    // video.detections, video.events, audio.transcript_partial, audio.transcript_final.
    std::string typeUtf8;
    int slot = 0;
    long long timestamp100ns = 0;
    long long frameIndex = 0;
    bool ok = false;
    std::string rawJsonUtf8;
    std::string summaryUtf8;
    std::string statusUtf8;
    std::vector<AiDetection> detections;
    std::vector<AiEvent> events;

    // Audio result fields. These are ignored by video result handling.
    int audioSource = 0;
    long long chunkIndex = 0;
    long long startTimestamp100ns = 0;
    long long endTimestamp100ns = 0;
    std::string srcLangUtf8;
    std::string dstLangUtf8;
    std::string textUtf8;
    std::string translationUtf8;
    bool isFinal = false;
};

enum AiTransportType
{
    AI_TRANSPORT_HTTP = 0,
    AI_TRANSPORT_WEBSOCKET = 1,
    AI_TRANSPORT_SHARED_MEMORY = 2
};

struct AiInputConfig
{
    int slot = 0;
    int targetFps = 1;
    int jpegQuality = 85;
    AiTransportType transport = AI_TRANSPORT_WEBSOCKET;
    std::wstring endpoint = L"ws://127.0.0.1:8766/v1/ai/stream";
    std::string modeUtf8 = "yolo";
    std::string promptUtf8 = "Analyze this video frame and return a short JSON result.";
};

struct AiAudioInputConfig
{
    int audioSource = 0;
    int targetSampleRate = 16000;
    int channels = 1;
    int bitsPerSample = 16;
    int chunkMs = 500;
    std::wstring endpoint = L"ws://127.0.0.1:8766/v1/ai/stream";
    std::string srcLangUtf8 = "auto";
    std::string dstLangUtf8 = "en";
};

static inline AiTransportType AiTransportFromEndpoint(const std::wstring& endpoint)
{
    if (_wcsnicmp(endpoint.c_str(), L"ws://", 5) == 0 ||
        _wcsnicmp(endpoint.c_str(), L"wss://", 6) == 0) {
        return AI_TRANSPORT_WEBSOCKET;
    }
    if (_wcsnicmp(endpoint.c_str(), L"shm://", 6) == 0) {
        return AI_TRANSPORT_SHARED_MEMORY;
    }
    return AI_TRANSPORT_HTTP;
}

static inline std::wstring AiUtf8ToWide(const std::string& text)
{
    if (text.empty()) return std::wstring();
    int len = MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, NULL, 0);
    if (len <= 0) return std::wstring(text.begin(), text.end());
    std::wstring out((size_t)len, L'\0');
    MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, &out[0], len);
    if (!out.empty() && out.back() == L'\0') out.pop_back();
    return out;
}

static inline std::string AiWideToUtf8(const std::wstring& text)
{
    if (text.empty()) return std::string();
    int len = WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, NULL, 0, NULL, NULL);
    if (len <= 0) return std::string(text.begin(), text.end());
    std::string out((size_t)len, '\0');
    WideCharToMultiByte(CP_UTF8, 0, text.c_str(), -1, &out[0], len, NULL, NULL);
    if (!out.empty() && out.back() == '\0') out.pop_back();
    return out;
}
