cmake_minimum_required(VERSION 3.16)
project(tinyserve C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

# Find libuv — try pkg-config first, fall back to find_path/find_library
# (fallback enables cross-compilation where pkg-config is unavailable)
set(LIBUV_FOUND OFF)

if(NOT LIBUV_INCLUDE_DIRS OR NOT LIBUV_LIBRARIES)
    find_package(PkgConfig QUIET)
    if(PkgConfig_FOUND)
        pkg_check_modules(LIBUV libuv)
    endif()
endif()

if(NOT LIBUV_FOUND)
    find_path(LIBUV_INCLUDE_DIRS uv.h
        HINTS ${CMAKE_PREFIX_PATH}/include /usr/include /usr/local/include)
    find_library(LIBUV_LIBRARIES NAMES uv uv_a
        HINTS ${CMAKE_PREFIX_PATH}/lib /usr/lib /usr/local/lib)
    if(LIBUV_INCLUDE_DIRS AND LIBUV_LIBRARIES)
        set(LIBUV_FOUND ON)
    endif()
endif()

if(NOT LIBUV_FOUND AND NOT LIBUV_INCLUDE_DIRS)
    message(FATAL_ERROR "libuv not found. Install libuv or set -DCMAKE_PREFIX_PATH=<libuv-install-dir>")
endif()

# Probe for getrandom() (Linux 3.17+) / arc4random_buf (BSD, macOS).
include(CheckSymbolExists)
check_symbol_exists(getrandom      "sys/random.h" TS_HAVE_GETRANDOM)
check_symbol_exists(arc4random_buf "stdlib.h"    TS_HAVE_ARC4RANDOM_BUF)

add_executable(tinyserve
    src/main.c
    src/log.c
    src/mime.c
    src/path_utils.c
    src/config.c
    src/http_parser.c
    src/http_response.c
    src/auth.c
    src/range.c
    src/file_serve.c
    src/route.c
    src/proxy.c
    src/server.c
)

target_include_directories(tinyserve PRIVATE
    ${LIBUV_INCLUDE_DIRS}
    src
)

target_link_libraries(tinyserve PRIVATE
    ${LIBUV_LIBRARIES}
)

if(LIBUV_LIBRARY_DIRS)
    target_link_directories(tinyserve PRIVATE
        ${LIBUV_LIBRARY_DIRS}
    )
endif()

if(TS_HAVE_GETRANDOM)
    target_compile_definitions(tinyserve PRIVATE TS_HAVE_GETRANDOM=1)
endif()
if(TS_HAVE_ARC4RANDOM_BUF)
    target_compile_definitions(tinyserve PRIVATE TS_HAVE_ARC4RANDOM_BUF=1)
endif()

# Compiler warnings
target_compile_options(tinyserve PRIVATE
    -Wall -Wextra -Wpedantic -Wno-unused-parameter
)

# Platform-specific settings
if(APPLE)
    target_compile_definitions(tinyserve PRIVATE TS_PLATFORM_MACOS)
elseif(UNIX)
    target_compile_definitions(tinyserve PRIVATE TS_PLATFORM_LINUX)
    # Link pthread/dl/rt for static libuv on Linux
    target_link_libraries(tinyserve PRIVATE pthread dl)
endif()

install(TARGETS tinyserve RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

# ── Install man page (gzip on Debian via dh; here keep raw) ────────────
include(GNUInstallDirs)
install(FILES man/tinyserve.1
    DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
)

# ── Hardening (Release) ─────────────────────────────────────────────────
# Enabled for Release builds (which is what Debian uses by default via
# dh_auto_configure). Distributions that want different flags can pass
# -DTS_NO_HARDENING=ON or override CFLAGS/LDFLAGS.
#
# The -Wl,-z,relro / -Wl,-z,now flags are GNU-ld specific and not
# accepted by Apple's ld; restrict to Linux to keep the macOS dev
# build green. macOS already enables ASLR / NX / stack-canaries by
# default at the OS / toolchain level.
if(NOT TS_NO_HARDENING)
    if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
        target_compile_options(tinyserve PRIVATE
            -D_FORTIFY_SOURCE=2
            -fstack-protector-strong
            -fPIE
        )
        if(UNIX AND NOT APPLE)
            target_compile_options(tinyserve PRIVATE
                -fstack-clash-protection
            )
            target_link_options(tinyserve PRIVATE
                -pie
                -Wl,-z,relro
                -Wl,-z,now
            )
        else()
            target_link_options(tinyserve PRIVATE -pie)
        endif()
    endif()
endif()

# ── Tests ────────────────────────────────────────────────────────────────
enable_testing()
add_subdirectory(tests)
