package handler

import (
	"encoding/json"
	"net/http"

	"git.yeij.top/AskaEth/Cyrene/platform-bridge/internal/bridge"
	"git.yeij.top/AskaEth/Cyrene/platform-bridge/internal/config"
)

var validPlatformTypes = map[string]bool{
	"obv11": true, "telegram": true, "webhook": true,
	"wechat": true, "feishu": true, "discord": true,
}

// ConfigHandler exposes CRUD endpoints for platform configs.
type ConfigHandler struct {
	store     *config.Store
	router    *bridge.PlatformRouter
	onChanged func(name, platform string, enabled bool, fields map[string]string)
}

func NewConfigHandler(store *config.Store, router *bridge.PlatformRouter) *ConfigHandler {
	return &ConfigHandler{store: store, router: router}
}

// SetOnConfigChanged sets a callback invoked after config is saved or deleted.
func (h *ConfigHandler) SetOnConfigChanged(fn func(name, platform string, enabled bool, fields map[string]string)) {
	h.onChanged = fn
}

func (h *ConfigHandler) RegisterRoutes(mux *http.ServeMux) {
	mux.HandleFunc("/api/v1/configs", h.listConfigs)
	mux.HandleFunc("/api/v1/configs/", h.handleConfig)
}

func (h *ConfigHandler) listConfigs(w http.ResponseWriter, r *http.Request) {
	configs := h.store.List()

	type configSummary struct {
		Name      string            `json:"name"`
		Platform  string            `json:"platform"`
		Enabled   bool              `json:"enabled"`
		Label     string            `json:"label,omitempty"`
		Fields    map[string]string `json:"fields"`
		UpdatedAt string            `json:"updated_at"`
		Connected bool              `json:"connected"`
	}

	var result []configSummary
	for _, c := range configs {
		connected := false
		if a, err := h.router.GetAdapter(c.Name); err == nil {
			connected = a.IsConnected()
		}
		platform := c.Platform
		if platform == "" {
			platform = c.Name
		}
		result = append(result, configSummary{
			Name:      c.Name,
			Platform:  platform,
			Enabled:   c.Enabled,
			Label:     c.Label,
			Fields:    c.Fields,
			UpdatedAt: c.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
			Connected: connected,
		})
	}
	// Also include platforms that exist as adapters but have no config yet.
	for _, name := range h.router.ListAdapters() {
		found := false
		for _, c := range configs {
			if c.Name == name {
				found = true
				break
			}
		}
		if !found {
			connected := false
			if a, err := h.router.GetAdapter(name); err == nil {
				connected = a.IsConnected()
			}
			result = append(result, configSummary{
				Name:      name,
				Platform:  name,
				Enabled:   false,
				Fields:    map[string]string{},
				Connected: connected,
			})
		}
	}
	if result == nil {
		result = []configSummary{}
	}
	writeJSON(w, http.StatusOK, map[string]interface{}{
		"configs": result,
		"total":   len(result),
	})
}

func (h *ConfigHandler) handleConfig(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Path[len("/api/v1/configs/"):]
	if name == "" {
		writeJSON(w, http.StatusBadRequest, errResp("missing config name"))
		return
	}

	switch r.Method {
	case "GET":
		h.getConfig(w, r, name)
	case "POST", "PUT":
		h.saveConfig(w, r, name)
	case "DELETE":
		h.deleteConfig(w, r, name)
	default:
		writeJSON(w, http.StatusMethodNotAllowed, errResp("method not allowed"))
	}
}

func (h *ConfigHandler) getConfig(w http.ResponseWriter, r *http.Request, name string) {
	cfg, err := h.store.Get(name)
	if err != nil {
		writeJSON(w, http.StatusNotFound, errResp(err.Error()))
		return
	}
	connected := false
	if a, err := h.router.GetAdapter(name); err == nil {
		connected = a.IsConnected()
	}
	writeJSON(w, http.StatusOK, map[string]interface{}{
		"name":       cfg.Name,
		"platform":   cfg.Platform,
		"enabled":    cfg.Enabled,
		"label":      cfg.Label,
		"fields":     cfg.Fields,
		"updated_at":  cfg.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
		"connected":  connected,
	})
}

func (h *ConfigHandler) saveConfig(w http.ResponseWriter, r *http.Request, name string) {
	var body struct {
		Platform *string           `json:"platform"`
		Enabled  *bool             `json:"enabled"`
		Label    string            `json:"label"`
		Fields   map[string]string `json:"fields"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeJSON(w, http.StatusBadRequest, errResp("invalid JSON: "+err.Error()))
		return
	}

	platform := name
	if body.Platform != nil && *body.Platform != "" {
		platform = *body.Platform
	}
	if !validPlatformTypes[platform] {
		writeJSON(w, http.StatusBadRequest, errResp("unknown or missing platform type: "+platform))
		return
	}

	enabled := true
	if body.Enabled != nil {
		enabled = *body.Enabled
	}

	fields := body.Fields
	if fields == nil {
		fields = make(map[string]string)
	}

	cfg := config.PlatformConfig{
		Name:     name,
		Platform: platform,
		Enabled:  enabled,
		Label:    body.Label,
		Fields:   fields,
	}
	if err := h.store.Set(cfg); err != nil {
		writeJSON(w, http.StatusInternalServerError, errResp(err.Error()))
		return
	}

	// Trigger hot-reload.
	if h.onChanged != nil {
		h.onChanged(name, platform, enabled, fields)
	}

	writeJSON(w, http.StatusOK, map[string]interface{}{
		"name":     name,
		"platform": platform,
		"enabled":  enabled,
		"label":    body.Label,
		"fields":   fields,
		"status":   "saved",
	})
}

func (h *ConfigHandler) deleteConfig(w http.ResponseWriter, r *http.Request, name string) {
	// Get platform type before deleting (needed for onChanged callback).
	platform := name
	if cfg, err := h.store.Get(name); err == nil && cfg.Platform != "" {
		platform = cfg.Platform
	}

	if err := h.store.Delete(name); err != nil {
		writeJSON(w, http.StatusNotFound, errResp(err.Error()))
		return
	}

	// Trigger hot-reload: disable and clear fields.
	if h.onChanged != nil {
		h.onChanged(name, platform, false, nil)
	}

	writeJSON(w, http.StatusOK, map[string]string{"status": "deleted", "name": name})
}
