#!/usr/bin/env bash
set -euo pipefail

# 一键启动本地 WebUI：
# - 后端 FastAPI: 127.0.0.1:8765
# - 前端 Next.js: 127.0.0.1:3000
# - PID 和日志统一写入 .port_sessions，重复执行会清理上一次由本脚本启动的进程。

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
RUN_DIR="${ROOT_DIR}/.port_sessions"
ENV_FILE="${ROOT_DIR}/.env.deploy"
if [[ -f "${ENV_FILE}" ]]; then
	# shellcheck disable=SC1090
	source "${ENV_FILE}"
fi
BACKEND_HOST="${CLAW_BACKEND_HOST:-0.0.0.0}"
BACKEND_PORT="${CLAW_BACKEND_PORT:-8765}"
FRONTEND_HOST="${CLAW_FRONTEND_HOST:-0.0.0.0}"
FRONTEND_PORT="${CLAW_FRONTEND_PORT:-3000}"
BACKEND_URL="http://${BACKEND_HOST}:${BACKEND_PORT}"
FRONTEND_URL="http://${FRONTEND_HOST}:${FRONTEND_PORT}"
PYTHON_BIN="${CLAW_PYTHON_BIN:-${ROOT_DIR}/.venv/bin/python}"
if [[ ! -x "${PYTHON_BIN}" ]]; then
	PYTHON_BIN="python3"
fi
LOCAL_IPV4_ORIGINS="$(ifconfig 2>/dev/null | awk '/inet / && $2 !~ /^127\\./ {print $2}' | awk '!seen[$0]++' | paste -sd, -)"
DEFAULT_ALLOWED_DEV_ORIGINS="localhost,127.0.0.1,0.0.0.0"
if [[ -n "${LOCAL_IPV4_ORIGINS}" ]]; then
	DEFAULT_ALLOWED_DEV_ORIGINS="${DEFAULT_ALLOWED_DEV_ORIGINS},${LOCAL_IPV4_ORIGINS}"
	while IFS= read -r local_ip; do
		[[ -z "${local_ip}" ]] && continue
		DEFAULT_ALLOWED_DEV_ORIGINS="${DEFAULT_ALLOWED_DEV_ORIGINS},${local_ip}:${FRONTEND_PORT}"
	done < <(printf "%s\n" "${LOCAL_IPV4_ORIGINS}" | tr "," "\n")
fi

mkdir -p "${RUN_DIR}"

stop_pid_file() {
	local pid_file="$1"
	local name="$2"
	if [[ ! -f "${pid_file}" ]]; then
		return
	fi
	local pid
	pid="$(cat "${pid_file}" 2>/dev/null || true)"
	if [[ -n "${pid}" ]] && kill -0 "${pid}" 2>/dev/null; then
		echo "Stopping previous ${name} (${pid})..."
		kill "${pid}" 2>/dev/null || true
		for _ in {1..20}; do
			if ! kill -0 "${pid}" 2>/dev/null; then
				break
			fi
			sleep 0.1
		done
		if kill -0 "${pid}" 2>/dev/null; then
			kill -9 "${pid}" 2>/dev/null || true
		fi
	fi
	rm -f "${pid_file}"
}

stop_port_listener() {
	local port="$1"
	local name="$2"
	local pids
	pids="$(lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true)"
	if [[ -z "${pids}" ]]; then
		return
	fi
	echo "Stopping ${name} listener(s) on port ${port}: ${pids//$'\n'/ }..."
	while IFS= read -r pid; do
		[[ -z "${pid}" ]] && continue
		kill "${pid}" 2>/dev/null || true
	done <<<"${pids}"
	for _ in {1..20}; do
		if ! lsof -tiTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1; then
			return
		fi
		sleep 0.1
	done
	while IFS= read -r pid; do
		[[ -z "${pid}" ]] && continue
		kill -9 "${pid}" 2>/dev/null || true
	done <<<"${pids}"
}

wait_for_url() {
	local url="$1"
	local name="$2"
	local log_file="$3"
	for _ in {1..80}; do
		if curl -fsS "${url}" >/dev/null 2>&1; then
			echo "${name} ready: ${url}"
			return 0
		fi
		sleep 0.25
	done
	echo "${name} did not become ready: ${url}" >&2
	echo "---- ${name} log tail ----" >&2
	tail -80 "${log_file}" >&2 || true
	return 1
}

shell_quote() {
	printf "%q" "$1"
}

start_detached_process() {
	local name="$1"
	local pid_file="$2"
	local log_file="$3"
	local work_dir="$4"
	shift 4
	local command="cd $(shell_quote "${work_dir}") && echo \$\$ > $(shell_quote "${pid_file}") && exec"
	local arg
	for arg in "$@"; do
		command+=" $(shell_quote "${arg}")"
	done
	command+=" >$(shell_quote "${log_file}") 2>&1"

	if command -v screen >/dev/null 2>&1; then
		screen -dmS "claw-${name}" bash -lc "${command}"
	else
		(
			cd "${work_dir}"
			nohup "$@" >"${log_file}" 2>&1 &
			echo "$!" >"${pid_file}"
		)
	fi
}

stop_pid_file "${RUN_DIR}/webui-frontend.pid" "frontend"
stop_pid_file "${RUN_DIR}/webui-backend.pid" "backend"
stop_port_listener "${FRONTEND_PORT}" "frontend"
stop_port_listener "${BACKEND_PORT}" "backend"

if [[ -z "${OPENAI_API_KEY:-}" ]]; then
	echo "OPENAI_API_KEY is not configured." >&2
	echo "Run scripts/deploy-ubuntu.sh once, or create ${ENV_FILE} from .env.deploy.example." >&2
fi
export OPENAI_API_KEY="${OPENAI_API_KEY:-}"
export OPENAI_BASE_URL="${OPENAI_BASE_URL:-http://model.mify.ai.srv/v1}"
export OPENAI_MODEL="${OPENAI_MODEL:-tongyi/deepseek-v4-pro}"
export OPENAI_TIMEOUT_SECONDS="${OPENAI_TIMEOUT_SECONDS:-3600}"

BACKEND_LOG="${RUN_DIR}/webui-backend.log"
FRONTEND_LOG="${RUN_DIR}/webui-frontend.log"

echo "Starting backend on ${BACKEND_URL}..."
start_detached_process "backend" "${RUN_DIR}/webui-backend.pid" "${BACKEND_LOG}" "${ROOT_DIR}" \
	"${PYTHON_BIN}" -m src.gui \
		--host "${BACKEND_HOST}" \
		--port "${BACKEND_PORT}" \
		--cwd "${ROOT_DIR}" \
		--timeout-seconds "${OPENAI_TIMEOUT_SECONDS}" \
		--session-dir "${RUN_DIR}/agent" \
		--allow-write \
		--allow-shell \
		--no-browser

wait_for_url "${BACKEND_URL}/api/state" "backend" "${BACKEND_LOG}"

echo "Starting frontend on ${FRONTEND_URL}..."
export CLAW_API_URL="${BACKEND_URL}"
export CLAW_ALLOWED_DEV_ORIGINS="${CLAW_ALLOWED_DEV_ORIGINS:-${DEFAULT_ALLOWED_DEV_ORIGINS}}"
start_detached_process "frontend" "${RUN_DIR}/webui-frontend.pid" "${FRONTEND_LOG}" "${ROOT_DIR}/frontend/app" \
	npm run dev -- --hostname "${FRONTEND_HOST}" --port "${FRONTEND_PORT}"

wait_for_url "${FRONTEND_URL}" "frontend" "${FRONTEND_LOG}"

cat <<EOF

WebUI started.
  Frontend: ${FRONTEND_URL}
  Backend : ${BACKEND_URL}
  Logs    : ${RUN_DIR}/webui-frontend.log
            ${RUN_DIR}/webui-backend.log

Stop:
  kill \$(cat "${RUN_DIR}/webui-frontend.pid") \$(cat "${RUN_DIR}/webui-backend.pid")

EOF
