// cmd/fake-acp-agent 是集成测试用的 fake ACP agent，stdin/stdout 走 JSON-RPC。
//
// 行为通过 env 控制：
//
//	FAKE_ACP_HANG=true                    永不响应任何请求（测 handshake 超时）
//	FAKE_ACP_CRASH_AFTER_PROMPTS=N         处理完 N 个 prompt 后 os.Exit(1)
//	FAKE_ACP_FS_READ=path                  prompt 时发起 fs/read_text_file 请求该路径
//	FAKE_ACP_FS_WRITE=path:content         prompt 时发起 fs/write_text_file
//	FAKE_ACP_PROMPT_UPDATES=N              每 prompt 发 N 个 update（默认 3）
//	FAKE_ACP_PERMISSION=toolName           prompt 时发起 session/request_permission
//	                                       （options: allow_once/reject_once），阻塞等响应后再结束
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
)

type Message struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      json.RawMessage `json:"id,omitempty"`
	Method  string          `json:"method,omitempty"`
	Params  json.RawMessage `json:"params,omitempty"`
	Result  json.RawMessage `json:"result,omitempty"`
	Error   *RPCError       `json:"error,omitempty"`
}

type RPCError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

var (
	promptsHandled atomic.Int32
	nextServerID   atomic.Int64
)

func main() {
	if os.Getenv("FAKE_ACP_HANG") == "true" {
		select {} // 永不退出
	}

	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	for {
		line, err := in.ReadBytes('\n')
		if err != nil {
			return
		}
		var msg Message
		if err := json.Unmarshal(line, &msg); err != nil {
			continue
		}
		switch msg.Method {
		case "initialize":
			respond(out, msg.ID, map[string]any{
				"protocolVersion": 1,
				"agentInfo":       map[string]any{"name": "fake", "version": "0.0.0"},
			})
		case "session/new":
			respond(out, msg.ID, map[string]any{"sessionId": "fake-session-id"})
		case "session/prompt":
			handlePrompt(in, out, msg.ID)
		case "session/cancel":
			// ignore
		}
	}
}

func handlePrompt(in *bufio.Reader, out *bufio.Writer, id json.RawMessage) {
	updates := 3
	if v := os.Getenv("FAKE_ACP_PROMPT_UPDATES"); v != "" {
		if n, _ := strconv.Atoi(v); n > 0 {
			updates = n
		}
	}
	for i := 0; i < updates; i++ {
		notify(out, "session/update", map[string]any{
			"sessionId": "fake-session-id",
			"update": map[string]any{
				"sessionUpdate": "agent_message_chunk",
				"content":       []map[string]any{{"type": "text", "text": fmt.Sprintf("chunk %d", i)}},
			},
		})
		time.Sleep(10 * time.Millisecond)
	}

	if path := os.Getenv("FAKE_ACP_FS_READ"); path != "" {
		_ = doFsRead(out, path)
	}

	if spec := os.Getenv("FAKE_ACP_FS_WRITE"); spec != "" {
		parts := strings.SplitN(spec, ":", 2)
		if len(parts) == 2 {
			_ = doFsWrite(out, parts[0], parts[1])
		}
	}

	if tool := os.Getenv("FAKE_ACP_PERMISSION"); tool != "" {
		doRequestPermission(in, out, tool)
	}

	respond(out, id, map[string]any{"stopReason": "end_turn"})

	if maxStr := os.Getenv("FAKE_ACP_CRASH_AFTER_PROMPTS"); maxStr != "" {
		n, _ := strconv.Atoi(maxStr)
		count := promptsHandled.Add(1)
		if int(count) >= n {
			os.Exit(1)
		}
	}
}

func doFsRead(out *bufio.Writer, path string) error {
	id := nextServerID.Add(1)
	idJSON, _ := json.Marshal(id)
	body := mustJSON(Message{
		JSONRPC: "2.0", ID: idJSON, Method: "fs/read_text_file",
		Params: mustJSON(map[string]any{"sessionId": "fake-session-id", "path": path}),
	})
	_, _ = out.Write(body)
	_, _ = out.Write([]byte{'\n'})
	_ = out.Flush()
	return nil
}

func doFsWrite(out *bufio.Writer, path, content string) error {
	id := nextServerID.Add(1)
	idJSON, _ := json.Marshal(id)
	body := mustJSON(Message{
		JSONRPC: "2.0", ID: idJSON, Method: "fs/write_text_file",
		Params: mustJSON(map[string]any{"sessionId": "fake-session-id", "path": path, "content": content}),
	})
	_, _ = out.Write(body)
	_, _ = out.Write([]byte{'\n'})
	_ = out.Flush()
	return nil
}

// doRequestPermission 发起 session/request_permission 并阻塞读取 stdin 直到收到
// 匹配 id 的响应（期间忽略其它消息）。用于端到端验证人工审批/自动放行链路。
func doRequestPermission(in *bufio.Reader, out *bufio.Writer, tool string) {
	id := nextServerID.Add(1)
	idJSON, _ := json.Marshal(id)
	body := mustJSON(Message{
		JSONRPC: "2.0", ID: idJSON, Method: "session/request_permission",
		Params: mustJSON(map[string]any{
			"sessionId": "fake-session-id",
			"toolCall":  map[string]any{"name": tool},
			"options": []map[string]any{
				{"id": "allow_once", "name": "Allow"},
				{"id": "reject_once", "name": "Reject"},
			},
		}),
	})
	_, _ = out.Write(body)
	_, _ = out.Write([]byte{'\n'})
	_ = out.Flush()

	// 阻塞等待该 request 的响应（忽略中途其它帧）。
	want := string(idJSON)
	for {
		line, err := in.ReadBytes('\n')
		if err != nil {
			return
		}
		var m Message
		if err := json.Unmarshal(line, &m); err != nil {
			continue
		}
		if len(m.ID) > 0 && string(m.ID) == want && (m.Result != nil || m.Error != nil) {
			return
		}
	}
}

func respond(out *bufio.Writer, id json.RawMessage, result any) {
	body := mustJSON(Message{JSONRPC: "2.0", ID: id, Result: mustJSON(result)})
	_, _ = out.Write(body)
	_, _ = out.Write([]byte{'\n'})
	_ = out.Flush()
}

func notify(out *bufio.Writer, method string, params any) {
	body := mustJSON(Message{JSONRPC: "2.0", Method: method, Params: mustJSON(params)})
	_, _ = out.Write(body)
	_, _ = out.Write([]byte{'\n'})
	_ = out.Flush()
}

func mustJSON(v any) json.RawMessage {
	b, _ := json.Marshal(v)
	return b
}
