package api

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

	"github.com/muyue/muyue/internal/config"
	"github.com/muyue/muyue/internal/lsp"
	"github.com/muyue/muyue/internal/skills"
)

type SavedConversation struct {
	ID        string    `json:"id"`
	Title     string    `json:"title"`
	Summary   string    `json:"summary,omitempty"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	Messages  []MessageEntry `json:"messages,omitempty"`
}

type MessageEntry struct {
	ID      string `json:"id"`
	Role    string `json:"role"`
	Content string `json:"content"`
	Time    string `json:"time"`
}

type conversationsStore struct {
	Path  string
	Items []SavedConversation
}

func conversationsPath() string {
	dir, _ := config.ConfigDir()
	return filepath.Join(dir, "conversations.json")
}

func listConversations() ([]SavedConversation, error) {
	path := conversationsPath()
	data, err := os.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return []SavedConversation{}, nil
		}
		return nil, err
	}
	var store conversationsStore
	if err := json.Unmarshal(data, &store); err != nil {
		return []SavedConversation{}, nil
	}
	return store.Items, nil
}

func saveConversations(items []SavedConversation) error {
	path := conversationsPath()
	dir := filepath.Dir(path)
	os.MkdirAll(dir, 0755)
	data, err := json.MarshalIndent(struct {
		Items []SavedConversation `json:"items"`
	}{Items: items}, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(path, data, 0600)
}

func (s *Server) handleListConversations(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		writeError(w, "GET only", http.StatusMethodNotAllowed)
		return
	}
	convs, err := listConversations()
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	conv := s.convStore.Get()
	tokenInfo := s.convStore.ApproxTokenCountDetailed()
	
	writeJSON(w, map[string]interface{}{
		"conversations":    convs,
		"current_messages": conv,
		"tokens":           tokenInfo.total,
		"tokens_by_role":   tokenInfo.byRole,
		"summary":          s.convStore.GetSummary(),
	})
}

func (s *Server) handleDeleteConversation(w http.ResponseWriter, r *http.Request) {
	if r.Method != "DELETE" {
		writeError(w, "DELETE only", http.StatusMethodNotAllowed)
		return
	}
	id := strings.TrimPrefix(r.URL.Path, "/api/conversations/")
	id = strings.TrimPrefix(id, "/")
	if id == "" {
		s.convStore.Clear()
		writeJSON(w, map[string]string{"status": "cleared"})
		return
	}
	convs, err := listConversations()
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	filtered := make([]SavedConversation, 0, len(convs))
	found := false
	for _, c := range convs {
		if c.ID == id {
			found = true
			continue
		}
		filtered = append(filtered, c)
	}
	if !found {
		writeError(w, "conversation not found", http.StatusNotFound)
		return
	}
	if err := saveConversations(filtered); err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]string{"status": "deleted"})
}

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

	query := r.URL.Query().Get("q")
	if query == "" {
		writeError(w, "query parameter 'q' is required", http.StatusBadRequest)
		return
	}

	results := s.convStore.Search(query)
	writeJSON(w, map[string]interface{}{
		"query":   query,
		"results": results,
		"count":   len(results),
	})
}

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

	format := r.URL.Query().Get("format")
	if format == "markdown" || format == "md" {
		w.Header().Set("Content-Type", "text/markdown; charset=utf-8")
		w.Write([]byte(s.convStore.ExportMarkdown()))
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(s.convStore.ExportJSON()))
}

func (s *Server) handleLSPInstall(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		writeError(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	var body struct {
		Name string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, err.Error(), http.StatusBadRequest)
		return
	}
	if body.Name == "" {
		writeError(w, "name is required", http.StatusBadRequest)
		return
	}
	if err := lsp.InstallServer(body.Name); err != nil {
		writeJSON(w, map[string]interface{}{
			"success": false,
			"error":   err.Error(),
		})
		return
	}
	writeJSON(w, map[string]interface{}{
		"success": true,
		"server":  body.Name,
	})
}

func (s *Server) handleSkillsDeploy(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		writeError(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	var body struct {
		Name string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, err.Error(), http.StatusBadRequest)
		return
	}
	if body.Name != "" {
		skill, err := skills.Get(body.Name)
		if err != nil {
			writeError(w, err.Error(), http.StatusNotFound)
			return
		}
		if err := skills.Deploy(skill); err != nil {
			writeError(w, err.Error(), http.StatusInternalServerError)
			return
		}
		writeJSON(w, map[string]string{"status": "deployed", "skill": body.Name})
		return
	}
	if err := skills.DeployAll(); err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]string{"status": "all deployed"})
}

func (s *Server) handleSkillsUndeploy(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		writeError(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	var body struct {
		Name string `json:"name"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, err.Error(), http.StatusBadRequest)
		return
	}
	if body.Name == "" {
		writeError(w, "name is required", http.StatusBadRequest)
		return
	}
	if err := skills.Undeploy(body.Name); err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]string{"status": "undeployed", "skill": body.Name})
}

func (s *Server) handleSSHConnections(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		writeError(w, "GET only", http.StatusMethodNotAllowed)
		return
	}
	cfg, err := config.Load()
	if err != nil {
		writeError(w, err.Error(), http.StatusInternalServerError)
		return
	}
	writeJSON(w, map[string]interface{}{
		"connections": cfg.Terminal.SSH,
	})
}

func (s *Server) handleSSHTest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		writeError(w, "POST only", http.StatusMethodNotAllowed)
		return
	}
	var body struct {
		Host string `json:"host"`
		Port int    `json:"port"`
		User string `json:"user"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, err.Error(), http.StatusBadRequest)
		return
	}
	if body.Host == "" || body.User == "" {
		writeError(w, "host and user are required", http.StatusBadRequest)
		return
	}
	if body.Port == 0 {
		body.Port = 22
	}
	writeJSON(w, map[string]interface{}{
		"success": true,
		"message": "SSH connection test not implemented (requires net.DialTimeout)",
	})
}