@echo off
setlocal EnableExtensions EnableDelayedExpansion

set "ROOT_DIR=%~dp0"
pushd "%ROOT_DIR%" >nul

set "VENV_DIR=.venv"
set "VENV_PYTHON=%VENV_DIR%\Scripts\python.exe"
set "LOG_DIR=logs"
set "API_PID_FILE=%LOG_DIR%\api.pid"
set "FRONTEND_PID_FILE=%LOG_DIR%\frontend.pid"
set "API_LOG_FILE=%CD%\%LOG_DIR%\api.log"
set "FRONTEND_LOG_FILE=%CD%\%LOG_DIR%\frontend.log"

call :load_env
if not defined API_HOST set "API_HOST=0.0.0.0"
if not defined API_PORT set "API_PORT=8000"
if not defined FRONTEND_PORT set "FRONTEND_PORT=5173"
if not defined FRONTEND_MODE set "FRONTEND_MODE=dev"

if "%~1"=="" goto help
if /I "%~1"=="help" goto help
if /I "%~1"=="-h" goto help
if /I "%~1"=="--help" goto help
if /I "%~1"=="setup" goto setup
if /I "%~1"=="start" goto start
if /I "%~1"=="stop" goto stop
if /I "%~1"=="restart" goto restart
if /I "%~1"=="status" goto status
if /I "%~1"=="logs" goto logs

echo Unknown command: %~1
echo Use dev.bat help to see available commands.
exit /b 1

:help
echo.
echo ========================================
echo   AI+合规智能中枢统一脚本（Windows）
echo ========================================
echo.
echo Usage:
echo   dev.bat help
echo   dev.bat setup
echo   dev.bat start [all^|api^|frontend] [--foreground] [--mode dev^|static]
echo   dev.bat stop [all^|api^|frontend]
echo   dev.bat restart [all^|api^|frontend] [--mode dev^|static]
echo   dev.bat status
echo   dev.bat logs ^<api^|frontend^> [--follow]
echo.
echo Command details:
echo   help
echo     Show the full command list, default ports, log paths and examples.
echo.
echo   setup
echo     Create .venv if missing, install backend dependencies from backend\requirements.txt,
echo     run npm install in frontend, then report Docker base service status.
echo.
echo   start
echo     Start services. Default target is all.
echo     start api --foreground   Run uvicorn in the current window with --reload for debugging.
echo     start frontend --mode static   Build the frontend and serve frontend\dist as static files.
echo.
echo   stop
echo     Stop services. It first uses logs\*.pid, then falls back to listeners on the configured ports.
echo.
echo   restart
echo     Stop and then start the selected target.
echo.
echo   status
echo     Show API, frontend and Docker service status. API status also checks /health.
echo.
echo   logs
echo     Show the last 50 lines by default. Add --follow to stream updates.
echo.
echo Defaults:
echo   API_HOST      = %API_HOST%
echo   API_PORT      = %API_PORT%
echo   FRONTEND_PORT = %FRONTEND_PORT%
echo   FRONTEND_MODE = %FRONTEND_MODE%
echo   Log files     = logs\api.log, logs\frontend.log
echo.
echo Examples:
echo   dev.bat setup
echo   dev.bat start
echo   dev.bat start api --foreground
echo   dev.bat start frontend --mode static
echo   dev.bat restart frontend --mode dev
echo   dev.bat status
echo   dev.bat logs api --follow
echo.
exit /b 0

:setup
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
echo.
echo ========================================
echo   AI+合规智能中枢 - 环境初始化
echo ========================================
echo.
call :resolve_python_bootstrap || exit /b 1
call %PYTHON_BOOTSTRAP% -c "import sys; raise SystemExit(0 if sys.version_info ^>= (3, 10) else 1)" || (
    echo Python 3.10+ is required.
    exit /b 1
)

if not exist "%VENV_PYTHON%" (
    call %PYTHON_BOOTSTRAP% -m venv "%VENV_DIR%" || exit /b 1
    echo Created virtual environment: %VENV_DIR%
) else (
    echo Virtual environment already exists: %VENV_DIR%
)

"%VENV_PYTHON%" -m pip install --upgrade pip || exit /b 1
"%VENV_PYTHON%" -m pip install -r backend\requirements.txt || exit /b 1
echo Backend dependencies installed.

if not exist "frontend\package.json" (
    echo Frontend package.json not found.
    exit /b 1
)

where npm >nul 2>nul || (
    echo npm was not found. Install Node.js 20+ first.
    exit /b 1
)

pushd frontend >nul
call npm install || (
    popd >nul
    exit /b 1
)
popd >nul
echo Frontend dependencies installed.

echo.
echo Docker base services:
for %%C in (milvus minio redis postgres) do call :print_docker_status %%C

echo.
echo Setup complete.
echo   dev.bat start
echo   dev.bat status
echo   dev.bat logs api --follow
exit /b 0

:start
set "TARGET=all"
set "MODE=%FRONTEND_MODE%"
set "FOREGROUND=0"
if /I "%~2"=="all" set "TARGET=all"
if /I "%~2"=="api" set "TARGET=api"
if /I "%~2"=="frontend" set "TARGET=frontend"
call :parse_start_options %* || exit /b 1

if /I "%TARGET%"=="all" (
    if "%FOREGROUND%"=="1" (
        echo start all does not support --foreground.
        exit /b 1
    )
    call :start_api_background || exit /b 1
    call :start_frontend "%MODE%" || exit /b 1
    exit /b 0
)

if /I "%TARGET%"=="api" (
    if "%FOREGROUND%"=="1" (
        call :start_api_foreground
        exit /b %errorlevel%
    )
    call :start_api_background
    exit /b %errorlevel%
)

if /I "%TARGET%"=="frontend" (
    call :start_frontend "%MODE%"
    exit /b %errorlevel%
)

echo Invalid start target.
exit /b 1

:parse_start_options
set "MODE=%FRONTEND_MODE%"
set "FOREGROUND=0"
:parse_start_options_loop
if "%~1"=="" exit /b 0
if /I "%~1"=="start" (
    shift
    goto parse_start_options_loop
)
if /I "%~1"=="all" (
    shift
    goto parse_start_options_loop
)
if /I "%~1"=="api" (
    shift
    goto parse_start_options_loop
)
if /I "%~1"=="frontend" (
    shift
    goto parse_start_options_loop
)
if /I "%~1"=="--foreground" (
    set "FOREGROUND=1"
    shift
    goto parse_start_options_loop
)
if /I "%~1"=="--mode" (
    if "%~2"=="" (
        echo --mode requires dev or static.
        exit /b 1
    )
    set "MODE=%~2"
    call :validate_mode "%MODE%" || exit /b 1
    shift
    shift
    goto parse_start_options_loop
)
echo Unknown argument: %~1
exit /b 1

:stop
set "TARGET=all"
if /I "%~2"=="api" set "TARGET=api"
if /I "%~2"=="frontend" set "TARGET=frontend"

if /I "%TARGET%"=="all" (
    call :stop_frontend
    call :stop_api
    exit /b 0
)
if /I "%TARGET%"=="api" (
    call :stop_api
    exit /b 0
)
if /I "%TARGET%"=="frontend" (
    call :stop_frontend
    exit /b 0
)
echo Invalid stop target.
exit /b 1

:restart
set "TARGET=all"
set "MODE=%FRONTEND_MODE%"
if /I "%~2"=="api" set "TARGET=api"
if /I "%~2"=="frontend" set "TARGET=frontend"
call :parse_restart_options %* || exit /b 1

if /I "%TARGET%"=="all" (
    call :stop_frontend
    call :stop_api
    call :start_api_background || exit /b 1
    call :start_frontend "%MODE%" || exit /b 1
    exit /b 0
)
if /I "%TARGET%"=="api" (
    call :stop_api
    call :start_api_background
    exit /b %errorlevel%
)
if /I "%TARGET%"=="frontend" (
    call :stop_frontend
    call :start_frontend "%MODE%"
    exit /b %errorlevel%
)
echo Invalid restart target.
exit /b 1

:parse_restart_options
set "MODE=%FRONTEND_MODE%"
:parse_restart_options_loop
if "%~1"=="" exit /b 0
if /I "%~1"=="restart" (
    shift
    goto parse_restart_options_loop
)
if /I "%~1"=="all" (
    shift
    goto parse_restart_options_loop
)
if /I "%~1"=="api" (
    shift
    goto parse_restart_options_loop
)
if /I "%~1"=="frontend" (
    shift
    goto parse_restart_options_loop
)
if /I "%~1"=="--mode" (
    if "%~2"=="" (
        echo --mode requires dev or static.
        exit /b 1
    )
    set "MODE=%~2"
    call :validate_mode "%MODE%" || exit /b 1
    shift
    shift
    goto parse_restart_options_loop
)
echo Unknown argument: %~1
exit /b 1

:status
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
echo.
echo ========================================
echo   AI+合规智能中枢 - 服务状态
echo ========================================
echo.

echo API service:
set "API_PID="
set "API_RUNNING=0"
set "API_LISTENER="
set "API_DISPLAY_PID="
if exist "%API_PID_FILE%" set /p API_PID=<"%API_PID_FILE%"
if defined API_PID (
    call :pid_exists !API_PID!
    if errorlevel 1 (
        del /q "%API_PID_FILE%" >nul 2>nul
        set "API_PID="
    ) else (
        set "API_RUNNING=1"
        set "API_DISPLAY_PID=!API_PID!"
    )
)

if "%API_RUNNING%"=="1" goto api_running
call :get_listener_pid %API_PORT% API_LISTENER
if defined API_LISTENER goto api_listener
echo   Status: stopped
goto api_done

:api_running
echo   Status: running
if defined API_DISPLAY_PID echo   PID:    !API_DISPLAY_PID!
call :check_api_health
if errorlevel 1 (
    echo   Health:  failed
) else (
    echo   Health:  ok
)
goto api_done

:api_listener
echo   Status: running (no PID file)
echo   PID:    !API_LISTENER!
call :check_api_health
if errorlevel 1 (
    echo   Health:  failed
) else (
    echo   Health:  ok
)

:api_done
echo   URL:     http://localhost:%API_PORT%
echo   Docs:    http://localhost:%API_PORT%/docs
echo.

echo Frontend service:
set "FRONTEND_PID="
set "FRONTEND_RUNNING=0"
set "FRONTEND_LISTENER="
set "FRONTEND_DISPLAY_PID="
if exist "%FRONTEND_PID_FILE%" set /p FRONTEND_PID=<"%FRONTEND_PID_FILE%"
if defined FRONTEND_PID (
    call :pid_exists !FRONTEND_PID!
    if errorlevel 1 (
        del /q "%FRONTEND_PID_FILE%" >nul 2>nul
        set "FRONTEND_PID="
    ) else (
        set "FRONTEND_RUNNING=1"
        set "FRONTEND_DISPLAY_PID=!FRONTEND_PID!"
    )
)

if "%FRONTEND_RUNNING%"=="1" goto frontend_running
call :get_listener_pid %FRONTEND_PORT% FRONTEND_LISTENER
if defined FRONTEND_LISTENER goto frontend_listener
echo   Status: stopped
goto frontend_done

:frontend_running
echo   Status: running
if defined FRONTEND_DISPLAY_PID echo   PID:    !FRONTEND_DISPLAY_PID!
goto frontend_done

:frontend_listener
echo   Status: running (no PID file)
echo   PID:    !FRONTEND_LISTENER!

:frontend_done
echo   Mode:    %FRONTEND_MODE%
echo   URL:     http://localhost:%FRONTEND_PORT%
echo.

echo Docker services:
where docker >nul 2>nul || (
    echo   Docker not installed.
    exit /b 0
)
for %%C in (milvus minio redis postgres) do call :print_docker_status %%C
exit /b 0

:logs
if "%~2"=="" (
    echo Specify api or frontend.
    exit /b 1
)

if /I "%~2"=="api" (
    set "LOG_FILE=%API_LOG_FILE%"
)
if /I "%~2"=="frontend" (
    set "LOG_FILE=%FRONTEND_LOG_FILE%"
)

if not defined LOG_FILE (
    echo Unknown log target: %~2
    exit /b 1
)
if not exist "%LOG_FILE%" (
    echo Log file not found: %LOG_FILE%
    exit /b 1
)

if /I "%~3"=="--follow" (
    pwsh -NoProfile -Command "Get-Content -LiteralPath '%LOG_FILE%' -Wait"
) else (
    pwsh -NoProfile -Command "Get-Content -LiteralPath '%LOG_FILE%' -Tail 50"
)
exit /b %errorlevel%

:start_api_background
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
if not exist "%VENV_PYTHON%" (
    echo Virtual environment not found. Run dev.bat setup first.
    exit /b 1
)

set "EXISTING_PID="
if exist "%API_PID_FILE%" set /p EXISTING_PID=<"%API_PID_FILE%"
if defined EXISTING_PID (
    call :pid_exists %EXISTING_PID%
    if not errorlevel 1 (
        echo API is already running. PID: %EXISTING_PID%
        exit /b 0
    ) else del /q "%API_PID_FILE%" >nul 2>nul
)

for /f %%P in ('pwsh -NoProfile -Command "$p = Start-Process -FilePath 'pwsh' -ArgumentList '-NoProfile','-Command',('Set-Location ''%CD%''; $env:PYTHONPATH=''backend''; & ''.\%VENV_PYTHON%'' -m uvicorn app.main:app --host ''%API_HOST%'' --port ''%API_PORT%'' *^> ''%API_LOG_FILE%''') -WindowStyle Hidden -PassThru; $p.Id"') do set "API_PID=%%P"

if not defined API_PID (
    echo Failed to start API.
    exit /b 1
)

> "%API_PID_FILE%" echo %API_PID%
timeout /t 3 /nobreak >nul
call :pid_exists %API_PID%
if errorlevel 1 (
    del /q "%API_PID_FILE%" >nul 2>nul
    echo API failed to start. Check logs\api.log
    exit /b 1
)

echo API started. PID: %API_PID%
echo   URL:  http://localhost:%API_PORT%
echo   Docs: http://localhost:%API_PORT%/docs
echo   Log:  logs\api.log
exit /b 0

:start_api_foreground
if not exist "%VENV_PYTHON%" (
    echo Virtual environment not found. Run dev.bat setup first.
    exit /b 1
)

set "PYTHONPATH=backend;%PYTHONPATH%"
echo API running in foreground with reload enabled.
echo   URL:  http://localhost:%API_PORT%
echo   Docs: http://localhost:%API_PORT%/docs
"%VENV_PYTHON%" -m uvicorn app.main:app --host "%API_HOST%" --port "%API_PORT%" --reload
exit /b %errorlevel%

:start_frontend
set "MODE=%~1"
if "%MODE%"=="" set "MODE=%FRONTEND_MODE%"
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"

where npm >nul 2>nul || (
    echo npm was not found. Install Node.js 20+ first.
    exit /b 1
)

if not exist "frontend\node_modules\vite" (
    echo Frontend dependencies are missing. Running npm install...
    pushd frontend >nul
    call npm install || (
        popd >nul
        exit /b 1
    )
    popd >nul
)

set "EXISTING_PID="
if exist "%FRONTEND_PID_FILE%" set /p EXISTING_PID=<"%FRONTEND_PID_FILE%"
if defined EXISTING_PID (
    call :pid_exists %EXISTING_PID%
    if not errorlevel 1 (
        echo Frontend is already running. PID: %EXISTING_PID%
        exit /b 0
    ) else del /q "%FRONTEND_PID_FILE%" >nul 2>nul
)

if /I "%MODE%"=="static" (
    pushd frontend >nul
    call npm run build || (
        popd >nul
        exit /b 1
    )
    popd >nul
    call :resolve_python_bootstrap || exit /b 1
    for /f %%P in ('pwsh -NoProfile -Command "$p = Start-Process -FilePath 'pwsh' -ArgumentList '-NoProfile','-Command',('Set-Location ''%CD%''; & %PYTHON_BOOTSTRAP% -m http.server %FRONTEND_PORT% --bind 0.0.0.0 --directory frontend/dist *^> ''%FRONTEND_LOG_FILE%''') -WindowStyle Hidden -PassThru; $p.Id"') do set "FRONTEND_PID=%%P"
 ) else (
    for /f %%P in ('pwsh -NoProfile -Command "$p = Start-Process -FilePath 'pwsh' -ArgumentList '-NoProfile','-Command',('Set-Location ''%CD%''; & npm --prefix frontend run dev -- --host 0.0.0.0 --port %FRONTEND_PORT% *^> ''%FRONTEND_LOG_FILE%''') -WindowStyle Hidden -PassThru; $p.Id"') do set "FRONTEND_PID=%%P"
 )

if not defined FRONTEND_PID (
    echo Failed to start frontend.
    exit /b 1
)

> "%FRONTEND_PID_FILE%" echo %FRONTEND_PID%
timeout /t 4 /nobreak >nul
call :pid_exists %FRONTEND_PID%
if errorlevel 1 (
    del /q "%FRONTEND_PID_FILE%" >nul 2>nul
    echo Frontend failed to start. Check logs\frontend.log
    exit /b 1
)

echo Frontend started. PID: %FRONTEND_PID%
echo   URL:  http://localhost:%FRONTEND_PORT%
echo   Mode: %MODE%
echo   Log:  logs\frontend.log
exit /b 0

:stop_api
set "API_PID="
if exist "%API_PID_FILE%" set /p API_PID=<"%API_PID_FILE%"
if defined API_PID (
    call :stop_pid %API_PID%
    del /q "%API_PID_FILE%" >nul 2>nul
    echo API stopped.
    exit /b 0
)

call :get_listener_pid %API_PORT% API_PORT_PID
if defined API_PORT_PID (
    call :stop_pid %API_PORT_PID%
    echo Stopped process listening on API port %API_PORT%.
    exit /b 0
)
echo API is not running.
exit /b 0

:stop_frontend
set "FRONTEND_PID="
if exist "%FRONTEND_PID_FILE%" set /p FRONTEND_PID=<"%FRONTEND_PID_FILE%"
if defined FRONTEND_PID (
    call :stop_pid %FRONTEND_PID%
    del /q "%FRONTEND_PID_FILE%" >nul 2>nul
    echo Frontend stopped.
    exit /b 0
)

call :get_listener_pid %FRONTEND_PORT% FRONTEND_PORT_PID
if defined FRONTEND_PORT_PID (
    call :stop_pid %FRONTEND_PORT_PID%
    echo Stopped process listening on frontend port %FRONTEND_PORT%.
    exit /b 0
)
echo Frontend is not running.
exit /b 0

:validate_mode
if /I "%~1"=="dev" exit /b 0
if /I "%~1"=="static" exit /b 0
echo Invalid frontend mode: %~1
exit /b 1

:resolve_python_bootstrap
where python >nul 2>nul && (
    set "PYTHON_BOOTSTRAP=python"
    exit /b 0
)
where py >nul 2>nul && (
    set "PYTHON_BOOTSTRAP=py -3"
    exit /b 0
)
echo Python was not found.
exit /b 1

:load_env
 for %%K in (API_HOST API_PORT FRONTEND_PORT FRONTEND_MODE) do call :read_env %%K .env
 for %%K in (API_HOST API_PORT FRONTEND_PORT FRONTEND_MODE) do call :read_env %%K .env.development
 exit /b 0

:read_env
if "%~2"=="" exit /b 0
if not exist "%~2" exit /b 0
for /f "usebackq tokens=1,* delims==" %%A in (`findstr /r /b /c:"%~1=" "%~2" 2^>nul`) do set "%~1=%%B"
exit /b 0

:pid_exists
pwsh -NoProfile -Command "exit([int](-not [bool](Get-Process -Id %~1 -ErrorAction SilentlyContinue)))"
exit /b %errorlevel%

:stop_pid
pwsh -NoProfile -Command "$p = Get-Process -Id %~1 -ErrorAction SilentlyContinue; if ($p) { Stop-Process -Id %~1 -Force }"
exit /b 0

:get_listener_pid
set "%~2="
for /f %%P in ('pwsh -NoProfile -Command "(Get-NetTCPConnection -LocalPort %~1 -State Listen -ErrorAction SilentlyContinue ^| Select-Object -ExpandProperty OwningProcess -Unique ^| Select-Object -First 1)"') do set "%~2=%%P"
exit /b 0

:check_api_health
pwsh -NoProfile -Command "try { $r = Invoke-WebRequest -Uri 'http://localhost:%API_PORT%/health' -TimeoutSec 3 -UseBasicParsing; exit([int](-not ($r.Content -match 'healthy'))) } catch { exit 1 }"
exit /b %errorlevel%

:print_docker_status
docker ps --format "{{.Names}}" | findstr /x /c:"%~1" >nul && (
    echo   %~1: running
    exit /b 0
)
docker ps -a --format "{{.Names}}" | findstr /x /c:"%~1" >nul && (
    echo   %~1: stopped
    exit /b 0
)
echo   %~1: not created
exit /b 0
