##
# @file mpy_prepare.cmake
# @brief Pre-compilation header generation for MicroPython
# This file handles QSTR generation and other necessary headers
#/

# This file is included after LIB_SRCS is defined in CMakeLists.txt
# It uses LIB_SRCS to scan for QSTR usage and generate necessary headers

message(STATUS "MicroPython: Preparing build environment...")

########################################
# Setup directories
########################################
# Paths for QSTR generation
set(QSTR_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/qstr_build)
file(MAKE_DIRECTORY ${QSTR_BUILD_DIR})

# Python scripts for generation
set(MAKEQSTRDATA_PY ${MPY_PY_DIR}/makeqstrdata.py)
set(MAKEQSTRDEFS_PY ${MPY_PY_DIR}/makeqstrdefs.py)

########################################
# Generate mpversion.h
########################################
# Create mpversion.h with fixed content
# This must be done before QSTR processing as some files may include it
file(WRITE ${GENHDR_DIR}/mpversion.h
"// This file was generated by py/makeversionhdr.py
#define MICROPY_GIT_TAG \"v1.26.0\"
#define MICROPY_GIT_HASH \"4ce2dd2cd\"
#define MICROPY_BUILD_DATE \"2025-09-20\"
")

message(STATUS "MicroPython: mpversion.h created")

########################################
# Generate moduledefs.h
########################################
# Extract module definitions from source files
set(MODULEDEFS_GENERATED ${GENHDR_DIR}/moduledefs.h)
set(MODULEDEFS_COLLECTED ${QSTR_BUILD_DIR}/moduledefs.collected)
set(MAKEMODULEDEFS_PY ${MPY_PY_DIR}/makemoduledefs.py)

# Create custom command to collect module definitions
add_custom_command(
    OUTPUT ${MODULEDEFS_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "Collecting module definitions..."

    # Use Python script to extract MP_REGISTER_MODULE from all source files
    # This avoids CMake's issues with semicolons and quotes
    COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/extract_modules.py
        ${MODULEDEFS_COLLECTED}
        "MP_REGISTER_MODULE"
        ${LIB_SRCS}

    DEPENDS ${LIB_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/extract_modules.py
    COMMENT "Extracting module definitions from source files"
    VERBATIM
)

# Generate moduledefs.h using makemoduledefs.py
add_custom_command(
    OUTPUT ${MODULEDEFS_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "Generating moduledefs.h..."

    # Run makemoduledefs.py
    # The script expects a list of files or stdin input with module definitions
    COMMAND python3 ${MAKEMODULEDEFS_PY} ${MODULEDEFS_COLLECTED} > ${MODULEDEFS_GENERATED}

    DEPENDS ${MODULEDEFS_COLLECTED} ${MAKEMODULEDEFS_PY}
    COMMENT "Generating moduledefs.h"
    VERBATIM
)

message(STATUS "MicroPython: moduledefs.h generation configured")

########################################
# Generate root_pointers.h
########################################
# Extract root pointer definitions from source files
set(ROOT_POINTERS_GENERATED ${GENHDR_DIR}/root_pointers.h)
set(ROOT_POINTERS_COLLECTED ${QSTR_BUILD_DIR}/root_pointers.collected)
set(MAKE_ROOT_POINTERS_PY ${MPY_PY_DIR}/make_root_pointers.py)

# Collect root pointer definitions
add_custom_command(
    OUTPUT ${ROOT_POINTERS_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "Collecting root pointer definitions..."

    # Use Python script to extract MP_REGISTER_ROOT_POINTER from all source files
    COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/extract_modules.py
        ${ROOT_POINTERS_COLLECTED}
        "MP_REGISTER_ROOT_POINTER"
        ${LIB_SRCS}

    DEPENDS ${LIB_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/extract_modules.py
    COMMENT "Extracting root pointer definitions from source files"
    VERBATIM
)

# Generate root_pointers.h using make_root_pointers.py
add_custom_command(
    OUTPUT ${ROOT_POINTERS_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "Generating root_pointers.h..."

    # Run make_root_pointers.py
    COMMAND python3 ${MAKE_ROOT_POINTERS_PY} ${ROOT_POINTERS_COLLECTED} > ${ROOT_POINTERS_GENERATED}

    DEPENDS ${ROOT_POINTERS_COLLECTED} ${MAKE_ROOT_POINTERS_PY}
    COMMENT "Generating root_pointers.h"
    VERBATIM
)

message(STATUS "MicroPython: root_pointers.h generation configured")

########################################
# Generate compressed.data.h
########################################
# For compressed data (error messages, etc.)
set(COMPRESSED_DATA_GENERATED ${GENHDR_DIR}/compressed.data.h)
set(MAKECOMPRESSEDDATA_PY ${MPY_PY_DIR}/makecompresseddata.py)

# For minimal build, we'll create an empty compressed data file
# In full builds, this would compress error messages and other strings
add_custom_command(
    OUTPUT ${COMPRESSED_DATA_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "Generating compressed.data.h..."

    # For minimal build, create empty compressed data
    # Later this can be expanded to compress actual data
    COMMAND ${CMAKE_COMMAND} -E echo "// Auto-generated compressed data" > ${COMPRESSED_DATA_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "// Empty for minimal build" >> ${COMPRESSED_DATA_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "#define MP_COMPRESSED_DATA_LEN 0" >> ${COMPRESSED_DATA_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "const char mp_compressed_data[1] = {0};" >> ${COMPRESSED_DATA_GENERATED}

    COMMENT "Generating compressed.data.h (minimal)"
    VERBATIM
)

message(STATUS "MicroPython: compressed.data.h generation configured")

########################################
# QSTR Generation Process
########################################
# QSTR generation follows three steps:
# 1. Extract QSTR usage from source files
# 2. Collect and merge QSTR definitions
# 3. Generate final qstrdefs.generated.h

# Base QSTR definitions
set(QSTR_DEFS_BASE ${MPY_PY_DIR}/qstrdefs.h)
set(QSTR_DEFS_PORT ${PORT_DIR}/qstrdefsport.h)

# Generated files
set(QSTR_EXTRACTED ${QSTR_BUILD_DIR}/qstr_extracted.txt)
set(QSTR_COLLECTED ${GENHDR_DIR}/qstrdefs.collected.h)
set(QSTR_PREPROCESSED ${QSTR_BUILD_DIR}/qstrdefs.preprocessed.h)
set(QSTR_GENERATED ${GENHDR_DIR}/qstrdefs.generated.h)

# Create a list of all source files that need QSTR scanning
set(QSTR_SOURCES ${LIB_SRCS})

########################################
# Step 1: Extract QSTRs from source files
########################################
# This custom command extracts all MP_QSTR_* usage from source files
add_custom_command(
    OUTPUT ${QSTR_EXTRACTED}
    COMMAND ${CMAKE_COMMAND} -E echo "QSTR: Extracting from source files..."
    COMMAND ${CMAKE_COMMAND} -E remove -f ${QSTR_EXTRACTED}
    COMMAND ${CMAKE_COMMAND} -E touch ${QSTR_EXTRACTED}

    # Process each source file individually to avoid list passing issues
    COMMAND ${CMAKE_COMMAND}
        "-DSOURCE_FILES=${QSTR_SOURCES}"
        "-DOUTPUT_FILE=${QSTR_EXTRACTED}"
        -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/extract_qstr.cmake

    DEPENDS ${QSTR_SOURCES}
    COMMENT "Extracting QSTR definitions from source files"
    VERBATIM
)

########################################
# Step 2: Collect QSTRs into collected.h
########################################
# This merges base QSTRs, extracted QSTRs, and port-specific QSTRs
add_custom_command(
    OUTPUT ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "QSTR: Creating qstrdefs.collected.h..."

    # Start with configuration
    COMMAND ${CMAKE_COMMAND} -E echo "// Auto-generated QSTR definitions" > ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "// Configuration" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "QCFG(BYTES_IN_LEN, 1)" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "QCFG(BYTES_IN_HASH, 2)" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "" >> ${QSTR_COLLECTED}

    # Add base QSTRs from py/qstrdefs.h
    COMMAND ${CMAKE_COMMAND} -E echo "// Base QSTRs from py/qstrdefs.h" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND}
        -DINPUT_FILE=${QSTR_DEFS_BASE}
        -DOUTPUT_FILE=${QSTR_COLLECTED}
        -DMODE=APPEND_Q_LINES
        -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/process_qstr.cmake

    # Add extracted QSTRs
    COMMAND ${CMAKE_COMMAND} -E echo "" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND} -E echo "// Extracted QSTRs from source files" >> ${QSTR_COLLECTED}
    COMMAND ${CMAKE_COMMAND}
        -DINPUT_FILE=${QSTR_EXTRACTED}
        -DOUTPUT_FILE=${QSTR_COLLECTED}
        -DMODE=CONVERT_TO_Q
        -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/process_qstr.cmake

    # Add port-specific QSTRs if exists
    COMMAND ${CMAKE_COMMAND}
        -DINPUT_FILE=${QSTR_DEFS_PORT}
        -DOUTPUT_FILE=${QSTR_COLLECTED}
        -DMODE=APPEND_Q_LINES_IF_EXISTS
        -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/process_qstr.cmake

    DEPENDS ${QSTR_EXTRACTED} ${QSTR_DEFS_BASE}
    COMMENT "Collecting QSTR definitions"
    VERBATIM
)

########################################
# Step 3: Generate final qstrdefs.generated.h
########################################
# Use makeqstrdata.py to generate the final header with enums and data
add_custom_command(
    OUTPUT ${QSTR_GENERATED}
    COMMAND ${CMAKE_COMMAND} -E echo "QSTR: Generating qstrdefs.generated.h..."

    # First preprocess the collected file (simple copy for now)
    COMMAND ${CMAKE_COMMAND} -E copy ${QSTR_COLLECTED} ${QSTR_PREPROCESSED}

    # Run makeqstrdata.py
    COMMAND python3 ${MAKEQSTRDATA_PY} ${QSTR_PREPROCESSED} > ${QSTR_GENERATED}

    DEPENDS ${QSTR_COLLECTED} ${MAKEQSTRDATA_PY}
    COMMENT "Generating final QSTR header file"
    VERBATIM
)

########################################
# Create target for all generated headers
########################################
add_custom_target(mpy_generated_headers
    DEPENDS
        ${QSTR_GENERATED}
        ${MODULEDEFS_GENERATED}
        ${ROOT_POINTERS_GENERATED}
        ${COMPRESSED_DATA_GENERATED}
)

# Note: The following commands should be called after the library target is created:
# - target_include_directories(${MODULE_NAME} PRIVATE ${GENHDR_DIR})
# - add_dependencies(${MODULE_NAME} mpy_generated_headers)
# These are handled in the main CMakeLists.txt after add_library()

message(STATUS "MicroPython: QSTR generation configured")
message(STATUS "  Output: ${QSTR_GENERATED}")

# Note: Other header generation (mpversion.h, moduledefs.h, etc.)
# will be added here in future steps
