package room

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// saveWorkspace 保存文件到 workspace 目录，自动版本追踪
func (r *Room) saveWorkspace(filename, content string) {
	dir := filepath.Join(r.Dir, "workspace")
	os.MkdirAll(dir, 0755)
	fpath := filepath.Join(dir, filename)

	// 版本追踪：保存旧版本到数据库
	if r.Store != nil {
		if old, err := os.ReadFile(fpath); err == nil && len(old) > 0 {
			r.Store.InsertFileVersion(r.Config.Name, filename, string(old), "")
		}
	}

	os.WriteFile(fpath, []byte(content), 0644)
	r.emit(Event{Type: EvtWorkspaceFile, Filename: filename, Action: "updated"})
}

func (r *Room) listWorkspaceFiles() []string {
	dir := filepath.Join(r.Dir, "workspace")
	entries, err := os.ReadDir(dir)
	if err != nil {
		return nil
	}
	var files []string
	for _, e := range entries {
		if !e.IsDir() && !strings.HasPrefix(e.Name(), ".") {
			files = append(files, e.Name())
		}
	}
	return files
}

// buildWorkspaceContext 读取 workspace 目录下所有文件内容，作为上下文
func (r *Room) buildWorkspaceContext() string {
	wsDir := filepath.Join(r.Dir, "workspace")
	entries, err := os.ReadDir(wsDir)
	if err != nil {
		return ""
	}
	const perFileMax = 4000  // 单文件最大字符数
	const totalMax = 20000   // workspace 上下文总最大字符数
	var sb strings.Builder
	totalChars := 0
	for _, e := range entries {
		if e.IsDir() || strings.HasPrefix(e.Name(), ".") {
			continue
		}
		content, err := os.ReadFile(filepath.Join(wsDir, e.Name()))
		if err != nil || len(content) == 0 {
			continue
		}
		text := string(content)
		runes := []rune(text)
		if len(runes) > perFileMax {
			runes = runes[:perFileMax]
			text = string(runes) + "\n...(截断)"
		}
		if totalChars+len(runes) > totalMax {
			sb.WriteString(fmt.Sprintf("\n--- 📎 %s --- (已省略，超出上下文限制)\n", e.Name()))
			continue
		}
		sb.WriteString(fmt.Sprintf("\n--- 📎 %s ---\n%s\n", e.Name(), text))
		totalChars += len(runes)
	}
	if sb.Len() == 0 {
		return ""
	}
	return "<workspace_files>\n以下是团队已产出的文档，可供参考和评审：" + sb.String() + "</workspace_files>"
}

// hasTodoList 检查 workspace 中是否存在 TodoList.md
func (r *Room) hasTodoList() bool {
	fpath := filepath.Join(r.Dir, "workspace", "TodoList.md")
	_, err := os.Stat(fpath)
	return err == nil
}

// saveAgentOutput 统一处理成员产出的文件保存路由（旧路径兼容，无模板时使用）。
// 返回 (filename, routed)：routed=true 表示走了文件路由。
func (r *Room) saveAgentOutput(name, finalReply, task string) (string, bool) {
	if r.projectTemplate != nil {
		ownerFiles := r.findOwnerFiles(name)
		if len(ownerFiles) >= 1 {
			var targetFile *ProjectFile
			if len(ownerFiles) == 1 {
				targetFile = &ownerFiles[0]
			} else {
				title := extractTitle(finalReply)
				if title != "" {
					if tf := r.matchTemplateFile(title); tf != nil && tf.Owner == name {
						targetFile = tf
					}
				}
				if targetFile == nil {
					firstLine := strings.TrimSpace(strings.SplitN(finalReply, "\n", 2)[0])
					firstLine = strings.TrimLeft(firstLine, "# ")
					if firstLine != "" {
						for i := range ownerFiles {
							base := strings.TrimSuffix(ownerFiles[i].Path, ".md")
							if strings.Contains(firstLine, base) || strings.Contains(base, firstLine) {
								targetFile = &ownerFiles[i]
								break
							}
						}
					}
				}
				if targetFile == nil {
					for i := range ownerFiles {
						fpath := filepath.Join(r.Dir, "workspace", ownerFiles[i].Path)
						if _, err := os.Stat(fpath); os.IsNotExist(err) {
							targetFile = &ownerFiles[i]
							break
						}
					}
				}
				if targetFile == nil && len([]rune(finalReply)) > 200 {
					targetFile = &ownerFiles[len(ownerFiles)-1]
				}
			}

			if targetFile != nil {
				fileContent, _ := splitContentAndStatus(finalReply, targetFile.Path)
				if !strings.HasPrefix(strings.TrimSpace(fileContent), "# ") {
					docTitle := strings.TrimSuffix(targetFile.Path, ".md")
					fileContent = "# " + docTitle + "\n\n" + fileContent
				}
				r.saveWorkspace(targetFile.Path, fileContent)
				if r.memberArtifacts == nil {
					r.memberArtifacts = make(map[string]string)
				}
				r.memberArtifacts[name] = targetFile.Path
				r.emit(Event{Type: EvtTaskDone, Agent: name, Task: task})
				return targetFile.Path, true
			}
		}
	}

	// 降级：原有 isDocument 逻辑
	if isDocument(finalReply) {
		title := extractTitle(finalReply)
		if r.memberArtifacts == nil {
			r.memberArtifacts = make(map[string]string)
		}
		var filename string
		if existing, ok := r.memberArtifacts[name]; ok {
			filename = existing
		} else {
			filename = titleToFilename(title, name)
			r.memberArtifacts[name] = filename
		}
		r.saveWorkspace(filename, finalReply)
		r.emit(Event{Type: EvtArtifact, Agent: name, Filename: filename, Title: title})
		r.emit(Event{Type: EvtTaskDone, Agent: name, Task: task})
		return filename, true
	}

	// 纯交流型输出
	r.emit(Event{Type: EvtAgentMessage, Agent: name, Role: "member", Content: finalReply})
	r.lastActiveMember = name
	r.emit(Event{Type: EvtTaskDone, Agent: name, Task: task})
	return "", false
}

// splitDocuments 从文本中拆分出独立文档段落（旧路径兼容）。
func splitDocuments(text string) []string {
	parts := strings.Split("\n"+text, "\n# ")
	if len(parts) <= 1 {
		return nil
	}
	var docs []string
	for _, part := range parts[1:] {
		doc := "# " + part
		doc = strings.TrimSpace(doc)
		if len([]rune(doc)) > 200 {
			docs = append(docs, doc)
		}
	}
	return docs
}

// isDocument 判断内容是否为文档产出物
func isDocument(content string) bool {
	runeLen := len([]rune(content))
	hasH1 := strings.Contains(content, "\n# ") || strings.HasPrefix(content, "# ")
	if hasH1 && runeLen > 300 {
		return true
	}
	h2Count := strings.Count(content, "\n## ")
	if h2Count >= 2 && runeLen > 200 {
		return true
	}
	if strings.Contains(content, "《") && strings.Contains(content, "》") && runeLen > 300 {
		if strings.Count(content, "\n") > 5 {
			return true
		}
	}
	return false
}

// stripDocuments 从文本中去除文档段落，只保留非文档部分。
func (r *Room) stripDocuments(text string) string {
	docs := splitDocuments(text)
	if len(docs) == 0 {
		return text
	}
	result := text
	for _, doc := range docs {
		result = strings.Replace(result, doc, "", 1)
	}
	for strings.Contains(result, "\n\n\n") {
		result = strings.ReplaceAll(result, "\n\n\n", "\n\n")
	}
	return strings.TrimSpace(result)
}

// splitContentAndStatus 将 agent 输出分为文件内容和状态消息。
func splitContentAndStatus(reply, filename string) (fileContent, statusMsg string) {
	fileContent = reply
	name := strings.TrimSuffix(filename, ".md")
	statusMsg = fmt.Sprintf("已完成《%s》", name)
	return
}

// applyDocumentEdit 解析并应用文档编辑指令
func (r *Room) applyDocumentEdit(content string) (filename string, applied bool) {
	editRe := regexp.MustCompile(`(?s)<<<EDIT\s+(.+?)>>>\s*<<<FIND>>>\s*(.+?)\s*<<<REPLACE>>>\s*(.+?)\s*<<<END>>>`)
	matches := editRe.FindAllStringSubmatch(content, -1)
	if len(matches) == 0 {
		return "", false
	}
	for _, m := range matches {
		fname := strings.TrimSpace(m[1])
		oldText := strings.TrimSpace(m[2])
		newText := strings.TrimSpace(m[3])
		fpath := filepath.Join(r.Dir, "workspace", fname)
		data, err := os.ReadFile(fpath)
		if err != nil {
			continue
		}
		original := string(data)
		if !strings.Contains(original, oldText) {
			continue
		}
		updated := strings.Replace(original, oldText, newText, 1)
		r.saveWorkspace(fname, updated)
		filename = fname
		applied = true
	}
	return
}


