/**
 * @file qdx_port_win32.c
 * @brief Windows (WinSock2 + WinAPI) 平台移植层
 *
 * 目的：将 qdx_port.h 声明的 HAL 接口映射到 Windows API，
 *       使 QDXnetworkStack 库能够在 PC 端运行。
 *
 * 注意：本文件仅用于 PC 端 Demo 模拟，不适用于 MCU 移植。
 */

#include "qdx_port.h"

#include <process.h> /* _beginthreadex */
#include <stddef.h>
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>


/* ============================================================
 * 时间与延迟
 * ============================================================ */

/* 获取系统启动以来的毫秒数 */
uint32_t qdx_port_get_tick_ms(void) { return (uint32_t)GetTickCount(); }

/* 阻塞延迟指定毫秒 */
void qdx_port_delay_ms(uint32_t ms) { Sleep(ms); }

/* ============================================================
 * TCP 网络操作 (基于 WinSock2)
 * ============================================================ */

/**
 * @brief 创建 TCP 套接字并连接到远端
 *
 * 连接成功后设置 500ms 接收超时，防止接收线程永久阻塞。
 */
qdx_socket_t qdx_port_tcp_connect(const char *ip, uint16_t port) {
  SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (sock == INVALID_SOCKET) {
    return NULL;
  }

  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = inet_addr(ip);

  if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
    closesocket(sock);
    return NULL;
  }

  /* 设置接收超时 500ms，使 recv 线程可定期检查连接状态 */
  DWORD timeout_ms = 500;
  setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout_ms,
             sizeof(timeout_ms));

  printf("[Port] TCP 已连接: %s:%d\n", ip, port);

  /* 将 SOCKET 转为不透明指针（SOCKET 本身是 unsigned int 类型） */
  return (qdx_socket_t)(intptr_t)sock;
}

/* 关闭 TCP 套接字 */
void qdx_port_tcp_close(qdx_socket_t sock) {
  if (sock) {
    closesocket((SOCKET)(intptr_t)sock);
  }
}

/* TCP 发送 */
int32_t qdx_port_tcp_send(qdx_socket_t sock, const uint8_t *data,
                          uint32_t len) {
  if (!sock)
    return -1;
  int ret = send((SOCKET)(intptr_t)sock, (const char *)data, (int)len, 0);
  if (ret == SOCKET_ERROR) {
    return -1;
  }
  return (int32_t)ret;
}

/**
 * @brief TCP 接收（非阻塞/短超时）
 *
 * 返回值约定：
 *   > 0 : 实际收到的字节数
 *   = 0 : 超时无数据
 *   < 0 : 连接断开或错误
 */
int32_t qdx_port_tcp_recv(qdx_socket_t sock, uint8_t *buf, uint32_t max_len) {
  if (!sock)
    return -1;
  int ret = recv((SOCKET)(intptr_t)sock, (char *)buf, (int)max_len, 0);
  if (ret == SOCKET_ERROR) {
    int err = WSAGetLastError();
    /* WSAETIMEDOUT / WSAEWOULDBLOCK 表示超时，视为无数据可读 */
    if (err == WSAETIMEDOUT || err == WSAEWOULDBLOCK) {
      return 0;
    }
    return -1; /* 真实错误 */
  }
  if (ret == 0) {
    return -1; /* 服务端主动关闭连接 */
  }
  return (int32_t)ret;
}

/* ============================================================
 * 互斥锁 (基于 CRITICAL_SECTION)
 * ============================================================ */

/* 创建互斥锁 */
qdx_mutex_t qdx_port_mutex_create(void) {
  CRITICAL_SECTION *cs = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION));
  if (!cs)
    return NULL;
  InitializeCriticalSection(cs);
  return (qdx_mutex_t)cs;
}

/* 加锁 */
void qdx_port_mutex_lock(qdx_mutex_t mutex) {
  if (mutex) {
    EnterCriticalSection((CRITICAL_SECTION *)mutex);
  }
}

/* 解锁 */
void qdx_port_mutex_unlock(qdx_mutex_t mutex) {
  if (mutex) {
    LeaveCriticalSection((CRITICAL_SECTION *)mutex);
  }
}

/* 销毁互斥锁 */
void qdx_port_mutex_delete(qdx_mutex_t mutex) {
  if (mutex) {
    DeleteCriticalSection((CRITICAL_SECTION *)mutex);
    free(mutex);
  }
}

/* ============================================================
 * 线程 (基于 _beginthreadex)
 * ============================================================ */

/**
 * @brief 线程启动包装器
 *
 * 目的：_beginthreadex 要求 unsigned __stdcall 签名，
 *       而 qdx_thread_entry_t 是 void(*)(void*)，
 *       需要通过此包装器做签名适配。
 */
typedef struct {
  qdx_thread_entry_t entry;
  void *arg;
} ThreadWrapper_t;

static unsigned __stdcall thread_wrapper(void *param) {
  ThreadWrapper_t *tw = (ThreadWrapper_t *)param;
  qdx_thread_entry_t entry = tw->entry;
  void *arg = tw->arg;
  free(tw); /* 释放包装结构，生命周期结束 */
  entry(arg);
  return 0;
}

/* 创建后台线程 */
int8_t qdx_port_thread_create(const char *name, qdx_thread_entry_t entry,
                              void *arg, uint32_t stack_size,
                              uint8_t priority) {
  (void)name;     /* Windows 线程不直接支持命名 */
  (void)priority; /* 简化 Demo 不设线程优先级 */

  ThreadWrapper_t *tw = (ThreadWrapper_t *)malloc(sizeof(ThreadWrapper_t));
  if (!tw)
    return -1;
  tw->entry = entry;
  tw->arg = arg;

  HANDLE h =
      (HANDLE)_beginthreadex(NULL, stack_size, thread_wrapper, tw, 0, NULL);
  if (h == NULL) {
    free(tw);
    return -1;
  }

  /* 分离线程句柄，后台自动运行 */
  CloseHandle(h);
  return 0;
}
