project('cell', ['c', 'cpp'],
  version: '0.9.3',
  meson_version: '>=1.4',
  default_options : [ 'cpp_std=c++11'])

libtype = get_option('default_library') 

link = []
src = []

fs = import('fs')

add_project_arguments('-pedantic', language: ['c'])

git_tag_cmd = run_command('git', 'describe', '--tags', '--abbrev=0', check: false)
cell_version = 'unknown'
if git_tag_cmd.returncode() == 0
  cell_version = git_tag_cmd.stdout().strip()
endif

git_commit_cmd = run_command('git', 'rev-parse', '--short', 'HEAD', check: false)
cell_commit = 'unknown'
if git_commit_cmd.returncode() == 0
  cell_commit = git_commit_cmd.stdout().strip()
endif

# Important: pass the definitions without double-escaping quotes
add_project_arguments(
  '-DCELL_VERSION="' + cell_version + '"',
  '-DCELL_COMMIT="' + cell_commit + '"',
  language : 'c'
)

add_project_arguments('-Wno-incompatible-pointer-types', language: 'c')
add_project_arguments('-Wno-narrowing', language: 'cpp')
add_project_arguments('-Wno-missing-braces', language:'c')
add_project_arguments('-Wno-strict-prototypes', language:'c')
add_project_arguments('-Wno-unused-command-line-argument', language: 'c')
add_project_arguments('-Wno-unused-command-line-argument', language: 'cpp')

deps = []

if host_machine.system() == 'darwin'
  add_project_arguments('-x', 'objective-c', language: 'c')
  fworks = [
    'foundation',
    'metal',
    'audiotoolbox',
    'metalkit',
    'avfoundation',
    'quartzcore',
    'cocoa',
    'coreaudio',
    'coremedia',
    'gamecontroller',
    'forcefeedback',
    'iokit',
    'corefoundation',
    'corehaptics',
    'carbon',
    'uniformtypeidentifiers'
  ]
  foreach fkit : fworks
    deps += dependency('appleframeworks', modules: fkit)
  endforeach
endif

cmake = import('cmake')

# Try to find system-installed mbedtls first
mbedtls_dep = dependency('mbedtls', static: true, required: false)
mbedx509_dep = dependency('mbedx509', static: true, required: false)
mbedcrypto_dep = dependency('mbedcrypto', static: true, required: false)

if not mbedtls_dep.found() or not mbedx509_dep.found() or not mbedcrypto_dep.found()
  message('⚙  System mbedtls not found, building subproject...')
  mbedtls_opts = cmake.subproject_options()
  mbedtls_opts.add_cmake_defines({
    'ENABLE_PROGRAMS': 'OFF',           # Disable Mbed TLS programs
    'ENABLE_TESTING': 'OFF',           # Disable Mbed TLS tests
    'CMAKE_BUILD_TYPE': 'Release',     # Optimize for release
    'MBEDTLS_FATAL_WARNINGS': 'ON',    # Treat warnings as errors
    'USE_STATIC_MBEDTLS_LIBRARY': 'ON',# Build static libraries
    'USE_SHARED_MBEDTLS_LIBRARY': 'OFF'# Disable shared libraries
  })
  mbedtls_proj = cmake.subproject('mbedtls', options: mbedtls_opts)
  deps += [
    mbedtls_proj.dependency('mbedtls'),
    mbedtls_proj.dependency('mbedx509'),
    mbedtls_proj.dependency('mbedcrypto')
  ]
else
  deps += [mbedtls_dep, mbedx509_dep, mbedcrypto_dep]
endif

sdl3_opts = cmake.subproject_options()
sdl3_opts.add_cmake_defines({
  'SDL_STATIC': 'ON',
  'SDL_SHARED': 'OFF',
  'SDL_TEST': 'OFF',
  'CMAKE_BUILD_TYPE': 'Release',
  'SDL_THREADS': 'ON',
  'SDL_PIPEWIRE': 'ON',
  'SDL_PULSEAUDIO': 'ON',
})

cc = meson.get_compiler('c')

if host_machine.system() == 'darwin'
  deps += dependency('appleframeworks', modules: 'accelerate')
  add_project_arguments('-DACCELERATE_NEW_LAPACK=1', language:'c')
  add_project_arguments('-DACCELERATE_LAPACK_ILP64=1', language:'c')
endif

if host_machine.system() == 'linux'
  deps += cc.find_library('asound', required:true)
  deps += [dependency('x11'), dependency('xi'), dependency('xcursor'), dependency('egl'), dependency('gl')]
  deps += cc.find_library('blas', required:true)
  deps += cc.find_library('lapack', required:true)
endif

if host_machine.system() == 'windows'
  deps += cc.find_library('d3d11')
  deps += cc.find_library('ws2_32', required:true)
  # For Windows, you may need to install OpenBLAS or Intel MKL
  # and adjust these library names accordingly
  deps += cc.find_library('openblas', required:false)
  if not cc.find_library('openblas', required:false).found()
    deps += cc.find_library('blas', required:false)
    deps += cc.find_library('lapack', required:false)
  endif
  deps += cc.find_library('dbghelp')
  deps += cc.find_library('winmm')
  deps += cc.find_library('setupapi')
  deps += cc.find_library('imm32')
  deps += cc.find_library('version')
  deps += cc.find_library('cfgmgr32')
  deps += cc.find_library('bcrypt')
  sdl3_opts.add_cmake_defines({'HAVE_ISINF': '1'}) # Hack for MSYS2
  sdl3_opts.add_cmake_defines({'HAVE_ISNAN': '1'})
  link += '-static'
endif

if host_machine.system() == 'emscripten'
  link += '-sUSE_WEBGPU'
  # Use the pre-installed copy
  deps += dependency('sdl3',
                     static : true,
                     method : 'pkg-config',   # or 'cmake' if you prefer
                     required : true)
else
  # Try to find system-installed SDL3 first
  sdl3_dep = dependency('sdl3', static: true, required: false)
  
  if not sdl3_dep.found()
    message('⚙  System SDL3 not found, building subproject...')
    sdl3_proj = cmake.subproject('sdl3', options : sdl3_opts)
    deps     += sdl3_proj.dependency('SDL3-static')
  else
    deps += sdl3_dep
  endif
endif

miniz_dep = dependency('miniz', static: true, required: false)
if not miniz_dep.found()
  message('⚙  System miniz not found, building subproject...')
  deps += dependency('miniz', static:true)
else
  deps += miniz_dep
endif

# Try to find system-installed physfs first
physfs_dep = dependency('physfs', static: true, required: false)
if not physfs_dep.found()
  message('⚙  System physfs not found, building subproject...')
  deps += dependency('physfs', static:true)
else
  deps += physfs_dep
endif

deps += dependency('threads')
deps += dependency('mimalloc')

# Try to find system-installed chipmunk first
chipmunk_dep = dependency('chipmunk', static: true, required: false)
if not chipmunk_dep.found()
  message('⚙  System chipmunk not found, building subproject...')
  deps += dependency('chipmunk', static:true)
else
  deps += chipmunk_dep
endif

if host_machine.system() != 'emscripten'
  # Try to find system-installed enet first
  enet_dep = dependency('enet', static: true, required: false)
  if not enet_dep.found()
    message('⚙  System enet not found, building subproject...')
    deps += dependency('enet', static:true)
  else
    deps += enet_dep
  endif
  src += 'qjs_enet.c'

  tracy_opts = ['fibers=true', 'no_exit=true', 'libunwind_backtrace=true', 'on_demand=true']
  add_project_arguments('-DTRACY_ENABLE', language:['c','cpp'])
  
  # Try to find system-installed tracy first
  tracy_dep = dependency('tracy', static: true, required: false)
  if not tracy_dep.found()
    message('⚙  System tracy not found, building subproject...')
    deps += dependency('tracy', static:true, default_options:tracy_opts)
  else
    deps += tracy_dep
  endif

  src += 'qjs_dmon.c'
endif

# Try to find system-installed soloud first
soloud_dep = dependency('soloud', static: true, required: false)
if not soloud_dep.found()
  message('⚙  System soloud not found, building subproject...')
  deps += dependency('soloud', static:true)
else
  deps += soloud_dep
endif

# Try to find system-installed qrencode first
qr_dep = dependency('qrencode', static: true, required: false)
if not qr_dep.found()
  message('⚙  System qrencode not found, building subproject...')
  deps += dependency('libqrencode', static:true)
else
  deps += qr_dep
endif

# Storefront SDK support
storefront = get_option('storefront')
if storefront == 'steam'
  steam_sdk_path = meson.current_source_dir() / 'sdk'
  
  if host_machine.system() == 'darwin'
    steam_lib_path = steam_sdk_path / 'redistributable_bin' / 'osx' / 'libsteam_api.dylib'
  elif host_machine.system() == 'linux'
    steam_lib_path = steam_sdk_path / 'redistributable_bin' / 'linux64' / 'libsteam_api.so'
  elif host_machine.system() == 'windows'
    steam_lib_path = steam_sdk_path / 'redistributable_bin' / 'win64' / 'steam_api64.lib'
  else
    steam_lib_path = ''
  endif
  
  if fs.exists(steam_lib_path)
    steam_dep = declare_dependency(
      include_directories: include_directories('sdk/public'),
      link_args: [steam_lib_path]
    )
    deps += steam_dep
    src += 'qjs_steam.cpp'
    message('Steam SDK enabled')
  else
    error('Steam SDK required but not found at: ' + steam_lib_path)
  endif
else
  add_project_arguments('-DNSTEAM', language: ['c', 'cpp'])
  message('Storefront: ' + storefront)
endif

link_args = link
sources = []
src += [
  'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
  'render.c','simplex.c','spline.c', 'transform.c','cell.c',  'wildmatch.c',
  'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
  'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'qjs_num.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c', 'qjs_text.c'
]
# quirc src
src += [
  'thirdparty/quirc/quirc.c', 'thirdparty/quirc/decode.c',
  'thirdparty/quirc/identify.c', 'thirdparty/quirc/version_db.c'
]

# quickjs src
src += ['quickjs.c', 'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c']

imsrc = [
  'GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp',
  'imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp',
  'implot_items.cpp','implot.cpp','imgui_impl_sdlrenderer3.cpp','imgui_impl_sdl3.cpp',
  'imgui_impl_sdlgpu3.cpp'
]

srceng = 'source'
tp = srceng / 'thirdparty'
includes = [
  srceng, tp / 'cgltf', tp / 'imgui', tp / 'par', tp / 'stb',
  tp, tp / 'pl_mpeg/include', tp / 'quirc'
]

foreach file : src
  full_path = join_paths('source', file)
  sources += files(full_path)
endforeach

includers = []
foreach inc : includes
  includers += include_directories(inc)
endforeach

if host_machine.system() == 'windows'
  exe_ext = '.exe'
else
  exe_ext = ''
endif

strip_enabled = ['release', 'minsize'].contains(get_option('buildtype'))

if strip_enabled
  add_project_link_arguments('-s', language: ['c', 'cpp'])
endif

cell = executable('cell', sources,
  dependencies: deps,
  include_directories: includers,
  link_args: link,
  build_rpath: '$ORIGIN',
  install: true
)

cell_dep = declare_dependency(
  link_with: cell
)

tests = [
  'spawn_actor',
  'empty',
  'nota',
  'wota',
  'portalspawner',
  'overling',
  'send',
  'delay'
]

foreach file : tests
  test(file, cell, args:['tests/' + file])
endforeach
