package rest

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

	"github.com/explorer/backend/wallet"
)

func (s *Server) walletConnectHandler() *wallet.WalletConnect {
	return wallet.NewWalletConnect(s.chainID)
}

// handleWalletConnectConfig handles GET /api/v1/walletconnect/config
func (s *Server) handleWalletConnectConfig(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}
	writeJSON(w, http.StatusOK, s.walletConnectHandler().PublicConfig())
}

// handleWalletConnectMetadata handles GET /api/v1/walletconnect/metadata
func (s *Server) handleWalletConnectMetadata(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}
	writeJSON(w, http.StatusOK, map[string]interface{}{
		"name":        "DBIS Explorer",
		"description": "Chain 138 explorer by DBIS",
		"url":         "https://explorer.d-bis.org",
		"icons":       []string{"https://explorer.d-bis.org/favicon.ico"},
	})
}

// handleWalletConnectConnect handles POST /api/v1/walletconnect/connect
func (s *Server) handleWalletConnectConnect(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}

	response, err := s.walletConnectHandler().Connect(r.Context())
	if err != nil {
		writeJSON(w, http.StatusNotImplemented, response)
		return
	}
	writeJSON(w, http.StatusOK, response)
}

// handleWalletConnectSessionRegister handles POST /api/v1/walletconnect/session
func (s *Server) handleWalletConnectSessionRegister(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}

	var req struct {
		SessionID string `json:"sessionId"`
		Address   string `json:"address"`
		ChainID   int    `json:"chainId"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "bad_request", "invalid JSON body")
		return
	}

	session, err := s.walletConnectHandler().RegisterSession(r.Context(), req.SessionID, req.Address, req.ChainID)
	if err != nil {
		writeError(w, http.StatusBadRequest, "bad_request", err.Error())
		return
	}
	writeJSON(w, http.StatusOK, session)
}

// handleWalletConnectSession handles GET /api/v1/walletconnect/session/{id}
func (s *Server) handleWalletConnectSession(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
		return
	}

	sessionID := strings.TrimPrefix(r.URL.Path, "/api/v1/walletconnect/session/")
	sessionID = strings.Trim(sessionID, "/")
	if sessionID == "" || strings.Contains(sessionID, "/") {
		writeError(w, http.StatusBadRequest, "bad_request", "session id is required")
		return
	}

	session, err := s.walletConnectHandler().GetSession(r.Context(), sessionID)
	if err != nil {
		writeJSON(w, http.StatusNotFound, session)
		return
	}
	writeJSON(w, http.StatusOK, session)
}

// handleWalletConnectRoot dispatches walletconnect subroutes.
func (s *Server) handleWalletConnectRoot(w http.ResponseWriter, r *http.Request) {
	path := strings.TrimPrefix(r.URL.Path, "/api/v1/walletconnect")
	path = strings.Trim(path, "/")

	switch path {
	case "config":
		s.handleWalletConnectConfig(w, r)
	case "metadata":
		s.handleWalletConnectMetadata(w, r)
	case "connect":
		s.handleWalletConnectConnect(w, r)
	case "session":
		s.handleWalletConnectSessionRegister(w, r)
	case "":
		if r.Method != http.MethodGet {
			writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
			return
		}
		writeJSON(w, http.StatusOK, map[string]interface{}{
			"endpoints": []string{
				"/api/v1/walletconnect/config",
				"/api/v1/walletconnect/metadata",
				"/api/v1/walletconnect/connect",
				"POST /api/v1/walletconnect/session",
				"/api/v1/walletconnect/session/{sessionId}",
			},
			"fallbackAuth": "/api/v1/auth/wallet",
		})
	default:
		if strings.HasPrefix(path, "session/") {
			s.handleWalletConnectSession(w, r)
			return
		}
		writeError(w, http.StatusNotFound, "not_found", "walletconnect route not found")
	}
}
