package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/muyue/muyue/internal/config"
	"github.com/muyue/muyue/internal/mcpserver"
)

func (s *Server) handleFileContent(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		path := r.URL.Query().Get("path")
		if path == "" {
			writeError(w, "path parameter required", http.StatusBadRequest)
			return
		}

		home, _ := os.UserHomeDir()
		path = strings.ReplaceAll(path, "~", home)

		if !filepath.IsAbs(path) {
			writeError(w, "path must be absolute", http.StatusBadRequest)
			return
		}

		data, err := os.ReadFile(path)
		if err != nil {
			writeError(w, fmt.Sprintf("Error reading file: %v", err), http.StatusNotFound)
			return
		}

		ext := strings.ToLower(filepath.Ext(path))
		lang := "text"
		switch ext {
		case ".go":
			lang = "go"
		case ".js", ".jsx":
			lang = "javascript"
		case ".ts", ".tsx":
			lang = "typescript"
		case ".py":
			lang = "python"
		case ".json":
			lang = "json"
		case ".yaml", ".yml":
			lang = "yaml"
		case ".md":
			lang = "markdown"
		case ".css":
			lang = "css"
		case ".html":
			lang = "html"
		case ".sh", ".bash":
			lang = "shell"
		case ".rs":
			lang = "rust"
		case ".java":
			lang = "java"
		}

		stat, _ := os.Stat(path)
		modTime := ""
		if stat != nil {
			modTime = stat.ModTime().Format("2006-01-02T15:04:05Z07:00")
		}

		writeJSON(w, map[string]interface{}{
			"path":    path,
			"content": string(data),
			"lang":    lang,
			"size":    len(data),
			"modTime": modTime,
		})

	case http.MethodPut:
		var body struct {
			Path    string `json:"path"`
			Content string `json:"content"`
		}
		if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
			writeError(w, err.Error(), http.StatusBadRequest)
			return
		}

		if body.Path == "" {
			writeError(w, "path required", http.StatusBadRequest)
			return
		}

		home, _ := os.UserHomeDir()
		path := strings.ReplaceAll(body.Path, "~", home)

		if !filepath.IsAbs(path) {
			writeError(w, "path must be absolute", http.StatusBadRequest)
			return
		}

		dir := filepath.Dir(path)
		if err := os.MkdirAll(dir, 0755); err != nil {
			writeError(w, fmt.Sprintf("Error creating directory: %v", err), http.StatusInternalServerError)
			return
		}

		if err := os.WriteFile(path, []byte(body.Content), 0644); err != nil {
			writeError(w, fmt.Sprintf("Error writing file: %v", err), http.StatusInternalServerError)
			return
		}

		writeJSON(w, map[string]interface{}{
			"status": "ok",
			"path":   path,
			"size":   len(body.Content),
		})

	default:
		writeError(w, "GET/PUT only", http.StatusMethodNotAllowed)
	}
}

func (s *Server) handleMuyueMCPServerStatus(w http.ResponseWriter, r *http.Request) {
	writeJSON(w, map[string]interface{}{
		"enabled": s.mcpServer != nil,
		"running": s.mcpServer != nil,
		"port":    s.getMCPServerPort(),
	})
}

func (s *Server) handleMuyueMCPServerStart(w http.ResponseWriter, r *http.Request) {
	if s.mcpServer != nil {
		writeJSON(w, map[string]string{"status": "already_running"})
		return
	}
	s.startMCPServer()
	writeJSON(w, map[string]interface{}{
		"status": "started",
		"port":   s.getMCPServerPort(),
	})
}

func (s *Server) handleMuyueMCPServerStop(w http.ResponseWriter, r *http.Request) {
	if s.mcpServer == nil {
		writeJSON(w, map[string]string{"status": "not_running"})
		return
	}
	s.mcpServer.Stop()
	s.mcpServer = nil
	writeJSON(w, map[string]string{"status": "stopped"})
}

func (s *Server) getMCPServerPort() int {
	if s.mcpServer == nil {
		return 0
	}
	return s.mcpServer.Port()
}

func (s *Server) startMCPServer() {
	port := 8096
	if s.config != nil {
	}
	s.mcpServer = mcpserver.New(port)
	s.mcpServer.Start()
}

func (s *Server) handleAgentSessionsList(w http.ResponseWriter, r *http.Request) {
	sessions := s.agentTracker.Discover()
	writeJSON(w, map[string]interface{}{
		"sessions": sessions,
	})
}

func (s *Server) handleAgentSessionOutput(w http.ResponseWriter, r *http.Request) {
	id := strings.TrimPrefix(r.URL.Path, "/api/agent-sessions/")
	if id == "" {
		writeError(w, "session id required", http.StatusBadRequest)
		return
	}

	session := s.agentTracker.Get(id)
	if session == nil {
		writeError(w, "session not found", http.StatusNotFound)
		return
	}

	writeJSON(w, session)
}

func (s *Server) handleWorkspaceList(w http.ResponseWriter, r *http.Request) {
	dir, err := configWorkspacesDir()
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	entries, err := os.ReadDir(dir)
	if err != nil {
		if os.IsNotExist(err) {
			writeJSON(w, map[string]interface{}{"workspaces": []interface{}{}})
			return
		}
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var workspaces []map[string]interface{}
	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		if !strings.HasSuffix(entry.Name(), ".json") {
			continue
		}
		name := strings.TrimSuffix(entry.Name(), ".json")
		data, err := os.ReadFile(filepath.Join(dir, entry.Name()))
		if err != nil {
			continue
		}
		var ws map[string]interface{}
		if err := json.Unmarshal(data, &ws); err != nil {
			continue
		}
		ws["name"] = name
		workspaces = append(workspaces, ws)
	}

	if workspaces == nil {
		workspaces = []map[string]interface{}{}
	}

	writeJSON(w, map[string]interface{}{"workspaces": workspaces})
}

func (s *Server) handleWorkspaceSave(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		writeError(w, "POST only", http.StatusMethodNotAllowed)
		return
	}

	var body struct {
		Name   string `json:"name"`
		Layout string `json:"layout"`
		Tabs   string `json:"tabs"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, err.Error(), http.StatusBadRequest)
		return
	}

	if body.Name == "" {
		writeError(w, "name required", http.StatusBadRequest)
		return
	}

	dir, err := configWorkspacesDir()
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	wsData := map[string]interface{}{
		"name":    body.Name,
		"layout":  body.Layout,
		"tabs":    body.Tabs,
		"updated": fmt.Sprintf("%d", time.Now().Unix()),
	}

	data, err := json.MarshalIndent(wsData, "", "  ")
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if err := os.WriteFile(filepath.Join(dir, body.Name+".json"), data, 0644); err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	writeJSON(w, map[string]string{"status": "ok"})
}

func (s *Server) handleWorkspaceGet(w http.ResponseWriter, r *http.Request) {
	name := strings.TrimPrefix(r.URL.Path, "/api/workspace/")
	if name == "" {
		writeError(w, "name required", http.StatusBadRequest)
		return
	}

	if r.Method == "DELETE" {
		dir, err := configWorkspacesDir()
		if err != nil {
			writeError(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err := os.Remove(filepath.Join(dir, name+".json")); err != nil {
			writeError(w, "workspace not found", http.StatusNotFound)
			return
		}
		writeJSON(w, map[string]string{"status": "ok"})
		return
	}

	dir, err := configWorkspacesDir()
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	data, err := os.ReadFile(filepath.Join(dir, name+".json"))
	if err != nil {
		writeError(w, "workspace not found", http.StatusNotFound)
		return
	}

	var result map[string]interface{}
	json.Unmarshal(data, &result)
	writeJSON(w, result)
}

func configWorkspacesDir() (string, error) {
	configDir, err := config.ConfigDir()
	if err != nil {
		return "", err
	}
	dir := filepath.Join(configDir, "workspaces")
	if err := os.MkdirAll(dir, 0755); err != nil {
		return "", fmt.Errorf("create workspaces dir: %w", err)
	}
	return dir, nil
}
