package handlers

import (
	"context"
	"encoding/json"
	"errors"
	"io/fs"
	"os"
	"strings"

	"github.com/yan1h/agent-coding-workflow/internal/acp/pathsafe"
)

// FsReadHandler handles fs/read_text_file (spec §5.4).
type FsReadHandler struct{}

// NewFsReadHandler constructs an FsReadHandler.
func NewFsReadHandler() *FsReadHandler { return &FsReadHandler{} }

// fsReadParams is the ACP-protocol input for fs/read_text_file.
type fsReadParams struct {
	SessionID string `json:"sessionId"`
	Path      string `json:"path"`
	Line      *int   `json:"line,omitempty"`
	Limit     *int   `json:"limit,omitempty"`
}

type fsReadResult struct {
	Content string `json:"content"`
}

// Handle reads a file inside sess.CwdPath, returning content (with optional
// line/limit slicing). Returns FsError for path-escape or read failure.
func (h *FsReadHandler) Handle(_ context.Context, sess SessionContext, paramsJSON json.RawMessage) FsResult {
	var p fsReadParams
	if err := json.Unmarshal(paramsJSON, &p); err != nil {
		return FsResult{Err: &FsError{Code: -32602, Message: "invalid params: " + err.Error()}}
	}
	abs, err := resolveSafePath(sess.CwdPath, p.Path)
	if err != nil {
		return FsResult{Err: &FsError{Code: -32001, Message: err.Error()}}
	}
	data, err := os.ReadFile(abs)
	if err != nil {
		if errors.Is(err, fs.ErrNotExist) {
			return FsResult{Err: &FsError{Code: -32603, Message: "file not found"}}
		}
		return FsResult{Err: &FsError{Code: -32603, Message: "read: " + err.Error()}}
	}
	content := string(data)
	if p.Line != nil || p.Limit != nil {
		content = sliceLines(content, p.Line, p.Limit)
	}
	out, _ := json.Marshal(fsReadResult{Content: content})
	return FsResult{OK: out}
}

// sliceLines returns lines[line:line+limit] joined by "\n".
// line is 0-based; limit caps the line count.
func sliceLines(s string, line, limit *int) string {
	lines := strings.Split(s, "\n")
	start := 0
	if line != nil && *line > 0 {
		start = *line
	}
	if start > len(lines) {
		start = len(lines)
	}
	end := len(lines)
	if limit != nil && *limit >= 0 {
		// overflow-safe：用剩余行数为上限做钳制，避免 start+*limit 在 *limit 很大
		// （如 math.MaxInt）时整数溢出为负，绕过下界判断后导致 lines[start:end] panic。
		remaining := len(lines) - start
		if *limit < remaining {
			end = start + *limit
		}
	}
	return strings.Join(lines[start:end], "\n")
}

// resolveSafePath 委托共享实现 pathsafe.ResolveSafePath。
// handlers 子包不能 import internal/acp 主包（acp 依赖 handlers，会循环），
// 故校验逻辑抽到 internal/acp/pathsafe 子包共用。
func resolveSafePath(cwd, requested string) (string, error) {
	return pathsafe.ResolveSafePath(cwd, requested)
}
