@echo off
setlocal enabledelayedexpansion

REM ============================================
REM Queue Management Script - Windows CMD Version
REM Function: Security audit file queue management
REM ============================================

REM Queue filename
set "QUEUE_FILENAME=.queue"

REM --- Global Variables ---
set "CMD="
set "SCAN_DIR_INPUT=."
set "SCAN_DIR_ABS="
set "QUEUE_FILE="
set "EXCLUDE_SCAN_FILES="
set "EXCLUDE_SCAN_DIRS="

REM --- Get current directory using %CD% (more reliable) ---
set "PWD=%CD%"

REM --- Parameter Parsing ---
if "%~1"=="" goto :usage
set "CMD=%~1"
if "%~2"=="" (
    set "SCAN_DIR_INPUT=."
) else (
    set "SCAN_DIR_INPUT=%~2"
)

REM --- Determine queue file location (always in current directory) ---
set "QUEUE_FILE=%PWD%\%QUEUE_FILENAME%"

REM --- Determine absolute path of scan directory ---
if "%SCAN_DIR_INPUT%"=="" (
    set "SCAN_DIR_ABS=%PWD%"
) else (
    if "%SCAN_DIR_INPUT:~0,1%"=="\" (
        set "SCAN_DIR_ABS=%SCAN_DIR_INPUT%"
    ) else (
        if "%SCAN_DIR_INPUT:~0,1%"=="/" (
            set "SCAN_DIR_ABS=%SCAN_DIR_INPUT%"
        ) else (
            set "SCAN_DIR_ABS=%PWD%\%SCAN_DIR_INPUT%"
        )
    )
)

REM --- Parse Environment Variables ---
if defined EXCLUDE_SCAN_FILES set "EXCLUDE_SCAN_FILES=%EXCLUDE_SCAN_FILES%"
if defined EXCLUDE_SCAN_DIRS set "EXCLUDE_SCAN_DIRS=%EXCLUDE_SCAN_DIRS%"

REM --- Command Dispatch ---
if /i "%CMD%"=="init" goto :func_init
if /i "%CMD%"=="status" goto :func_status
if /i "%CMD%"=="push" goto :func_push
if /i "%CMD%"=="pop" goto :func_pop
if /i "%CMD%"=="diff" goto :func_diff
if /i "%CMD%"=="clean" goto :func_clean

echo Error: Unknown command '%CMD%'
goto :usage

REM ============================================
REM Usage Information
REM ============================================
:usage
echo Usage: %0 ^<command^> [scan_directory]
echo.
echo Commands:
echo   init   : Scan directory and generate .queue file in current working directory
echo   status : Show remaining queue count in current working directory
echo   push ^<path1^> [path2...^]: Append files/directories to queue (multiple paths supported)
echo   pop    : Pop and output one file absolute path
echo   diff [git diff parameters...] : Add git diff results to queue
echo   clean  : Clean up
echo.
echo Environment Variables:
echo   EXCLUDE_SCAN_FILES: Space-separated glob patterns to exclude files
echo   EXCLUDE_SCAN_DIRS : Space-separated glob patterns to exclude directories
echo.
echo Notes:
echo   Scan directory supports relative paths.
echo   Queue file (.queue) is always in current working directory.
echo   File paths written to queue are absolute paths.
exit /b 1

REM ============================================
REM func_init: Scan directory to initialize queue
REM ============================================
:func_init
echo Current working directory: %PWD%
echo Scan target directory: %SCAN_DIR_ABS%

REM Check if scan directory exists
if not exist "%SCAN_DIR_ABS%" (
    echo Error: Scan directory [%SCAN_DIR_INPUT%] does not exist
    exit /b 1
)

REM Print exclude rules
if defined EXCLUDE_SCAN_FILES echo Exclude file patterns: %EXCLUDE_SCAN_FILES%
if defined EXCLUDE_SCAN_DIRS echo Exclude directory patterns: %EXCLUDE_SCAN_DIRS%

REM Clear queue file
type nul > "%QUEUE_FILE%"

REM Build parameters and execute search
set "TOTAL_COUNT=0"

for /r "%SCAN_DIR_ABS%" %%f in (*) do (
    set "FILE_PATH=%%f"
    call :check_and_add_file
)

REM Sort and deduplicate
call :dedup_queue

REM Statistics
for /f %%c in ('find /c /v "" ^< "%QUEUE_FILE%"') do set "TOTAL_COUNT=%%c"
echo.
echo ----------------------------------------
echo Total files: %TOTAL_COUNT%
echo ----------------------------------------
echo Queue file generated: %QUEUE_FILE%
goto :end

:check_and_add_file
REM Exclude .git directory
echo "%FILE_PATH%" | findstr /i /c:".git" >nul && exit /b 0
REM Exclude queue file itself
if /i "%FILE_PATH%"=="%QUEUE_FILE%" exit /b 0
REM Exclude exclude file patterns
if defined EXCLUDE_SCAN_FILES (
    for %%p in (%EXCLUDE_SCAN_FILES%) do (
        set "EXT=%%~xf"
        if /i "!EXT!"=="%%~p" exit /b 0
    )
)
REM Exclude exclude directory patterns
if defined EXCLUDE_SCAN_DIRS (
    for %%p in (%EXCLUDE_SCAN_DIRS%) do (
        echo "%FILE_PATH%" | findstr /i /c:"\\%%~p\\" >nul && exit /b 0
    )
)
REM Check if file is empty
for %%z in ("%FILE_PATH%") do if %%~zz==0 exit /b 0
REM Add to queue
echo %FILE_PATH% >> "%QUEUE_FILE%"
set /a TOTAL_COUNT+=1
exit /b 0

:dedup_queue
REM Sort and deduplicate: use sort + temporary file
if exist "%QUEUE_FILE%.sorted" del /f /q "%QUEUE_FILE%.sorted"
sort "%QUEUE_FILE%" /o "%QUEUE_FILE%.sorted"
if exist "%QUEUE_FILE%.sorted" (
    move /y "%QUEUE_FILE%.sorted" "%QUEUE_FILE%" >nul 2>&1
)
exit /b 0

REM ============================================
REM func_push: Add paths to queue
REM ============================================
:func_push
set "ADDED_TOTAL=0"
set "ITEM_COUNT=0"

REM Process arguments starting from %2 (the first path argument)
if not "%~2"=="" goto :push_args
echo Usage: queue.bat push ^<path1^> [path2...]
exit /b 1

:push_args
REM Handle multiple arguments - use a loop to process all
for %%a in (%~2 %~3 %~4 %~5 %~6 %~7 %~8 %~9) do (
    if not "%%a"=="" (
        if not "%%a"=="push" (
            call :add_single_item "%%a"
        )
    )
)
goto :push_show_result

:add_single_item
set "ITEM=%~1"
if "%ITEM%"=="" exit /b 0
if "%ITEM%"=="push" exit /b 0

REM Check if path contains more than one colon (Windows path issue)
for /f "tokens=1* delims=:" %%a in ("%ITEM%") do (
    echo %%b | findstr /r ":" >nul
    if not errorlevel 1 (
        echo Error: Path contains multiple colons. Windows paths should use # separator.
        echo Usage: push ^<path^>#^<start_line^>#^<line_count^>
        exit /b 1
    )
)

REM Check if ITEM uses # delimiter for range: path#start_line#line_count
echo %ITEM% | findstr /c:"#" >nul
if errorlevel 1 (
    REM No # found - normal path
    call :add_single_item_normal "%ITEM%"
    exit /b 0
)

REM Has # - try to parse as range format
REM Format: path#start_line#line_count
for /f "tokens=1,2,3 delims=#" %%a in ("%ITEM%") do (
    set "FILE_PATH=%%a"
    set "START_LINE=%%b"
    set "LINE_COUNT=%%c"
)

REM Validate we have all parts (both START_LINE and LINE_COUNT must be non-empty)
if "%START_LINE%"=="" exit /b 0
if "%LINE_COUNT%"=="" exit /b 0

REM Simple validation: check that START and LINE_COUNT look like numbers
REM Just check that they're not empty and don't contain path separators
if "%START_LINE%"=="" exit /b 0
if "%LINE_COUNT%"=="" exit /b 0

REM Check if file exists
if exist "%FILE_PATH%" (
    for %%f in ("%FILE_PATH%") do echo %%~ff#%START_LINE%#%LINE_COUNT% >> "%CD%\.queue"
    set /a ADDED_TOTAL+=1
) else (
    echo Warning: Path %FILE_PATH% does not exist
)
exit /b 0

REM ============================================
REM func_get_rel_path: Get relative path from absolute path
REM Parameters: %1 = path (path_to_convert(cd_path))
REM Output:     REL_PATH variable (global)
REM ============================================
:func_get_rel_path
setlocal
set "full_input=%~1"
set "cd_path=%~2"
for /f "tokens=1 delims=(" %%a in ("%full_input%") do set "file_path=%%a"
set "file_path=%file_path:"=%"
set "cd_path_orig=%cd_path:"=%"
set "len_cd=0"
REM Calculate length of cd_path
:calc_length
set "cd_path_temp=%cd_path_orig:~0,1%"
if defined cd_path_temp (
    set "cd_path_orig=%cd_path_orig:~1%"
    set /a len_cd+=1
    goto calc_length
)
REM Check if file_path starts with cd_path
set "compare_prefix="
if %len_cd% gtr 0 set "compare_prefix=%file_path:~0,%len_cd%"
if /i "%compare_prefix%"=="%cd_path%" (
    REM Prefix matches, extract relative part
    set /a "skip_len=%len_cd%+1"
    set "REL_PATH=%file_path:~%skip_len%"
) else (
    set "REL_PATH="
)
endlocal & set "REL_PATH=%REL_PATH%"
REM Convert backslashes to forward slashes for consistency
if defined REL_PATH set "REL_PATH=%REL_PATH:\=/%"
exit /b 0

:add_single_item_normal
set "NORMAL_ITEM=%~1"
if "%NORMAL_ITEM%"=="" exit /b 0

REM Check if path exists
if exist "%NORMAL_ITEM%" (
    if exist "%NORMAL_ITEM%\" (
        REM Is directory
        echo Adding files from directory: %NORMAL_ITEM%
        for /r "%NORMAL_ITEM%" %%f in (*) do (
            echo %%f >> "%CD%\.queue"
        )
    ) else (
        REM Is file - get absolute path
        for %%f in ("%NORMAL_ITEM%") do echo %%~ff >> "%CD%\.queue"
        for /f "tokens=1" %%n in ('find /c /v "" ^< "%CD%\.queue"') do set "ADDED_TOTAL=%%n"
    )
) else (
    echo Warning: Path %NORMAL_ITEM% does not exist
)
exit /b 0

:push_show_result
REM Always show queue status after push
call :dedup_queue_simple
for /f %%c in ('find /c /v "" ^< "%CD%\.queue"') do set "QUEUE_TOTAL=%%c"
echo ----------------------------------------
echo Queue total: %QUEUE_TOTAL%
exit /b 0

:dedup_queue_simple
sort "%CD%\.queue" /o "%CD%\.queue"
exit /b 0

:to_abs_path
set "INPUT_PATH=%~1"
if "!INPUT_PATH!"=="" (
    set "%2=%PWD%"
    exit /b 0
)
if "!INPUT_PATH:~0,1!"=="\" (
    set "%2=!INPUT_PATH!"
    exit /b 0
)
if "!INPUT_PATH:~0,1!"=="/" (
    set "%2=!INPUT_PATH!"
    exit /b 0
)
set "%2=%PWD%\!INPUT_PATH!"
exit /b 0

REM ============================================
REM func_status: Check queue status
REM ============================================
:func_status
echo Checking queue in: %CD%
if not exist "%CD%\.queue" (
    echo Note: No queue file found in current directory %CD%
    exit /b 1
)
for /f %%c in ('find /c /v "" ^< "%CD%\.queue"') do set "COUNT=%%c"
echo Current working directory: %CD%
echo Remaining files: %COUNT%
exit /b 0

REM ============================================
REM func_pop: Pop from queue head
REM ============================================
:func_pop
if not exist "%CD%\.queue" (
    echo Error: Queue is empty or not initialized
    exit /b 0
)

REM Read first line using set /p
set /p ENTRY=<"%CD%\.queue"

REM Check if ENTRY is empty
if "%ENTRY%"=="" (
    echo Queue is empty, cannot pop
    exit /b 0
)

REM Check if ENTRY contains # delimiter (range format: path#start#end)
echo %ENTRY% | findstr /c:"#" >nul
if errorlevel 1 (
    REM No # found - normal path
    echo Next audit file path: %ENTRY%
    REM Calculate relative path by checking if file path starts with current directory
    setlocal enabledelayedexpansion
    set "file_path=%ENTRY%"
    set "cd_path=%CD%"
    set "rel_path="
    REM Check if file_path starts with cd_path (case-insensitive)
    echo !file_path! | findstr /i /c:"!cd_path!" >nul && (
        REM Extract the relative part by removing the cd_path prefix
        for %%d in ("!cd_path!") do set "len=%%~zd"
        set /a "skip=len+1"
        set "rel_path=!file_path:~%skip%!"
        REM Remove drive letter if present (e.g., D:/)
        for /f "tokens=1* delims=:/" %%i in ("!rel_path!") do (
            if "%%j" neq "" set "rel_path=%%j"
        )
        REM Remove leading slash if present
        if "!rel_path:~0,1!"=="/" set "rel_path=!rel_path:~1!"
        if "!rel_path:~0,1!"=="\\" set "rel_path=!rel_path:~1!"
    )
    REM If no relative path found, use just filename
    if "!rel_path!"=="" for %%n in ("%ENTRY%") do set "rel_path=%%~nxn"
    REM Convert backslashes to forward slashes
    if defined rel_path set "rel_path=!rel_path:\=/!"
    REM Remove any leading slash that might have been introduced by conversion
    if "!rel_path:~0,1!"=="/" set "rel_path=!rel_path:~1!"
    echo ^> [Hint] The intermediate report output path: `^<output_dir^>/!rel_path!-report-0.json`
    endlocal
) else (
    REM Has # - parse as range format - output must be inside the loop
    for /f "tokens=1,2,3 delims=#" %%a in ("%ENTRY%") do (
        echo Next audit file path: %%a
        
        REM Calculate relative path and end line
        setlocal enabledelayedexpansion
        set "start_line=%%b"
        set "line_count=%%c"
        set /a "end_line=start_line + line_count - 1"
        if !end_line! lss !start_line! set "end_line=!start_line!"
        echo ^> [Diff Range] Start line: !start_line!, End line: !end_line!
        
        set "file_path=%%a"
        set "cd_path=%CD%"
        set "rel_path="
        REM Check if file_path starts with cd_path (case-insensitive)
        echo !file_path! | findstr /i /c:"!cd_path!" >nul && (
            REM Extract the relative part by removing the cd_path prefix
            for %%d in ("!cd_path!") do set "len=%%~zd"
            set /a "skip=len+1"
            set "rel_path=!file_path:~%skip%!"
            REM Remove drive letter if present (e.g., D:/)
            for /f "tokens=1* delims=:/" %%i in ("!rel_path!") do (
                if "%%j" neq "" set "rel_path=%%j"
            )
            REM Remove leading slash if present
            if "!rel_path:~0,1!"=="/" set "rel_path=!rel_path:~1!"
            if "!rel_path:~0,1!"=="\\" set "rel_path=!rel_path:~1!"
        )
        REM If no relative path found, use just filename
        if "!rel_path!"=="" for %%n in ("%%a") do set "rel_path=%%~nxn"
        REM Convert backslashes to forward slashes
        if defined rel_path set "rel_path=!rel_path:\=/!"
        REM Remove any leading slash that might have been introduced by conversion
        if "!rel_path:~0,1!"=="/" set "rel_path=!rel_path:~1!"
        echo ^> [Hint] The intermediate report output path: `^<output_dir^>/!rel_path!-L!start_line!-report-0.json`
        endlocal
    )
)

REM Delete first line
setlocal enabledelayedexpansion
set "file=%CD%\.queue"
set "temp=%CD%\.queue.tmp"
(
    for /f "skip=1 delims=" %%i in ('type "!file!"') do (
        set "line=%%i"
        if not "!line!"=="" echo !line!
    )
) > "!temp!"
endlocal
move /y "%CD%\.queue.tmp" "%CD%\.queue" >nul 2>&1

exit /b 0

REM ============================================
REM compute_rel_path: Compute relative path for file_path relative to cd_path
REM Uses global variables: file_path, cd_path
REM Sets: rel_path
REM ============================================
:compute_rel_path
set "rel_path="

REM Use simple substring extraction approach
REM Check if file_path is longer than cd_path and might start with it
REM We'll use a character-by-character comparison

set "fp=!file_path!"
set "cp=!cd_path!"
set "idx=0"

REM Find where paths diverge
:compare_chars
set "fc=!fp:~%idx%,1!"
set "fc1=!fc!"
if "!fc1:~0,1!"=="/" set "fc=\"
if "!fc1:~0,1!"=="/" set "fc=\"

set "cc=!cp:~%idx%,1!"
if not defined cc goto :paths_match
if not defined fc goto :no_match
if /i not "!fc!"=="!cc!" goto :no_match
set /a idx+=1
goto compare_chars

:paths_match
REM Paths match up to cd_path length, extract remainder
for %%d in ("!cp!") do set "len=0"
:count_len
set "c=!cp:~%len%,1%"
if defined c (
    set /a len+=1
    goto count_len
)
set /a skip=len+1
set "rel_path=!fp:~%skip%!"
exit /b 0

:no_match
REM Paths don't match, just use filename
for %%f in ("!file_path!") do set "rel_path=%%~nxf"
exit /b 0

REM ============================================
REM func_diff: Add git diff results to queue
REM ============================================
:func_diff
setlocal enabledelayedexpansion

REM 1. Check git environment
git rev-parse --is-inside-work-tree >nul 2>&1
if !errorlevel! neq 0 (
    echo Error: Current directory is not in a git repository
    exit /b 1
)

REM 2. Get Git root directory
for /f "delims=" %%g in ('git rev-parse --show-toplevel') do set "GIT_ROOT=%%g"

REM 3. Execute git diff
REM Use shift to get all arguments after "diff"
set "DIFF_ARGS="
:get_diff_args
shift
if "%~1"=="" goto :diff_args_done
set "DIFF_ARGS=!DIFF_ARGS! %~1"
goto :get_diff_args
:diff_args_done

REM Clear queue
type nul > "%QUEUE_FILE%"

REM 4. Parse git diff output
set "COUNT=0"
set "CURRENT_FILE="

REM Execute git diff and capture output line by line
set "DIFF_TEMP_FILE=%TEMP%\queue_diff_%RANDOM%.txt"
git diff --unified=0 %DIFF_ARGS% > "%DIFF_TEMP_FILE%" 2>&1

if not exist "%DIFF_TEMP_FILE%" (
    echo [ERROR] Failed to create diff output file.
    goto :end
)

REM Read from temp file
for /f "usebackq delims=" %%d in ("%DIFF_TEMP_FILE%") do (
    set "LINE=%%d"
    
    REM --- A. Parse file path ---
    REM Check if line starts with "+++ b/" or "+++ "
    if "!LINE:~0,4!"=="+++ " (
        for /f "tokens=2 delims= " %%p in ("!LINE!") do set "REL_PATH=%%p"
        
        REM Remove "b/" prefix if present
        if "!REL_PATH:~0,2!"=="b/" set "REL_PATH=!REL_PATH:~2!"
        if "!REL_PATH:~0,2!"=="b\\" set "REL_PATH=!REL_PATH:~2!"
        
        if "!REL_PATH!"=="/dev/null" (
            set "CURRENT_FILE="
        ) else (
            set "CURRENT_FILE=%GIT_ROOT%\!REL_PATH!"
            if not exist "!CURRENT_FILE!" (
                set "CURRENT_FILE="
            )
        )
    )
    
    REM --- B. Parse line range ---
    REM Check if line starts with "@@ "
    if defined CURRENT_FILE (
        if "!LINE:~0,3!"=="@@ " (
            REM Extract range part between @@
            for /f "tokens=1 delims=@" %%r in ("!LINE!") do set "RANGE=%%r"
            
            REM Extract the part after + sign
            for /f "tokens=2 delims=+" %%s in ("!RANGE!") do set "START=%%s"
            
            REM Extract start line number (before comma)
            for /f "tokens=1 delims=," %%t in ("!START!") do set "START_LINE=%%t"
            
            REM Trim leading space from START_LINE if needed
            for /f "tokens=* delims= " %%t in ("!START_LINE!") do set "START_LINE=%%t"
            
            REM Trim trailing space (using for loop to extract first token)
            for %%t in (!START_LINE!) do set "START_LINE=%%t"
            
            REM Default line count to 1
            set "LINE_COUNT=1"
            
            REM Check if there's a comma (indicating line count)
            if not "!START!"=="!START:,=!" (
                for /f "tokens=2 delims=," %%u in ("!START!") do set "LINE_COUNT=%%u"
            )
            
            REM Write to queue: absolute_path#start_line#line_count
            echo !CURRENT_FILE!#!START_LINE!#!LINE_COUNT! >> "%QUEUE_FILE%"
            set /a COUNT+=1
        )
    )
)

if exist "%DIFF_TEMP_FILE%" del "%DIFF_TEMP_FILE%"

echo ----------------------------------------
echo Written %COUNT% change blocks to queue
echo Queue file: %QUEUE_FILE%
echo ----------------------------------------
goto :end

REM ============================================
REM func_clean: Clean up queue
REM ============================================
:func_clean
if not exist "%CD%\.queue" (
    echo Error: Queue is empty or not initialized in current directory %CD%
    exit /b 1
)
for /f %%c in ('find /c /v "" ^< "%CD%\.queue"') do set COUNT=%%c
if %COUNT%==0 (
    del /f /q "%CD%\.queue" 2>nul
    if not exist "%CD%\.queue" (
        echo Queue cleaned up
    ) else (
        echo Cleanup failed
    )
    exit /b 0
)
echo Remaining files to audit: %COUNT%, cannot clean
exit /b 0

:end
