package mounts

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

const (
	codexManagedMCPBlockStart    = "# BEGIN XWORKMATE MANAGED MCP BLOCK"
	codexManagedMCPBlockEnd      = "# END XWORKMATE MANAGED MCP BLOCK"
	opencodeManagedMCPBlockStart = "# BEGIN XWORKMATE MANAGED MCP BLOCK"
	opencodeManagedMCPBlockEnd   = "# END XWORKMATE MANAGED MCP BLOCK"
)

var mcpServerSectionPattern = regexp.MustCompile(
	`(?m)^\[mcp_servers\.[^\]]+\]`,
)

func countMCPSections(content string) int {
	return len(mcpServerSectionPattern.FindAllStringIndex(content, -1))
}

func defaultCodexHome() string {
	home, err := os.UserHomeDir()
	if err != nil || strings.TrimSpace(home) == "" {
		return ""
	}
	return filepath.Join(home, ".codex")
}

func defaultOpencodeHome() string {
	home, err := os.UserHomeDir()
	if err != nil || strings.TrimSpace(home) == "" {
		return ""
	}
	return filepath.Join(home, ".opencode")
}

func defaultOpenClawHome() string {
	home, err := os.UserHomeDir()
	if err != nil || strings.TrimSpace(home) == "" {
		return ""
	}
	return filepath.Join(home, ".openclaw")
}

func stripManagedBlock(content, startMarker, endMarker string) string {
	if strings.TrimSpace(content) == "" {
		return content
	}

	remaining := content
	for {
		start := strings.Index(remaining, startMarker)
		if start < 0 {
			break
		}
		end := strings.Index(remaining[start:], endMarker)
		if end < 0 {
			remaining = remaining[:start]
			break
		}
		end += start
		remaining = remaining[:start] + remaining[end+len(endMarker):]
	}
	return remaining
}

func mergeManagedBlock(content, block, startMarker, endMarker string) string {
	preserved := strings.TrimRight(
		stripManagedBlock(content, startMarker, endMarker),
		"\n",
	)
	if preserved == "" {
		return block + "\n"
	}
	return preserved + "\n\n" + block + "\n"
}

func buildCodexManagedMCPBlock(servers []ManagedMCPServer) string {
	var buffer strings.Builder
	buffer.WriteString(codexManagedMCPBlockStart)
	buffer.WriteString("\n# Generated by XWorkmate - Managed MCP Server Configuration\n")
	_, _ = fmt.Fprintf(&buffer, "# Last updated: %s\n\n", time.Now().Format(time.RFC3339Nano))
	for _, server := range servers {
		_, _ = fmt.Fprintf(&buffer, "[mcp_servers.%s]\n", server.ID)
		_, _ = fmt.Fprintf(&buffer, "command = %q\n", server.Command)
		if len(server.Args) > 0 {
			_, _ = fmt.Fprintf(&buffer, "args = %s\n", formatTOMLArray(server.Args))
		}
		buffer.WriteString("\n")
	}
	buffer.WriteString(codexManagedMCPBlockEnd)
	return strings.TrimRight(buffer.String(), "\n")
}

func buildOpencodeManagedMCPBlock(servers []ManagedMCPServer) string {
	var buffer strings.Builder
	buffer.WriteString(opencodeManagedMCPBlockStart)
	buffer.WriteString("\n# Generated by XWorkmate - Managed MCP Server Configuration\n")
	_, _ = fmt.Fprintf(&buffer, "# Last updated: %s\n\n", time.Now().Format(time.RFC3339Nano))
	for _, server := range servers {
		_, _ = fmt.Fprintf(&buffer, "[mcp_servers.%s]\n", server.ID)
		if strings.TrimSpace(server.URL) != "" {
			_, _ = fmt.Fprintf(&buffer, "url = %q\n", strings.TrimSpace(server.URL))
		} else {
			buffer.WriteString("type = \"stdio\"\n")
			_, _ = fmt.Fprintf(&buffer, "command = %q\n", server.Command)
			if len(server.Args) > 0 {
				_, _ = fmt.Fprintf(&buffer, "args = %s\n", formatTOMLArray(server.Args))
			}
		}
		buffer.WriteString("\n")
	}
	buffer.WriteString(opencodeManagedMCPBlockEnd)
	return strings.TrimRight(buffer.String(), "\n")
}

func formatTOMLArray(items []string) string {
	if len(items) == 0 {
		return "[]"
	}
	var quoted []string
	for _, item := range items {
		quoted = append(quoted, fmt.Sprintf("%q", item))
	}
	return "[" + strings.Join(quoted, ", ") + "]"
}

func applyManagedBlock(configPath, block, startMarker, endMarker string) error {
	configDir := filepath.Dir(configPath)
	if err := os.MkdirAll(configDir, 0o755); err != nil {
		return err
	}

	content, err := os.ReadFile(configPath)
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	merged := mergeManagedBlock(string(content), block, startMarker, endMarker)
	return os.WriteFile(configPath, []byte(merged), 0o644)
}
