package rest

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

// Validation errors
var (
	ErrInvalidAddress     = fmt.Errorf("invalid address format")
	ErrInvalidHash        = fmt.Errorf("invalid hash format")
	ErrInvalidBlockNumber = fmt.Errorf("invalid block number")
)

// isValidHash validates if a string is a valid hex hash (0x + 64 hex chars)
func isValidHash(hash string) bool {
	if !strings.HasPrefix(hash, "0x") {
		return false
	}
	if len(hash) != 66 {
		return false
	}
	_, err := hex.DecodeString(hash[2:])
	return err == nil
}

// isValidAddress validates if a string is a valid Ethereum address (0x + 40 hex chars)
func isValidAddress(address string) bool {
	if !strings.HasPrefix(address, "0x") {
		return false
	}
	if len(address) != 42 {
		return false
	}
	_, err := hex.DecodeString(address[2:])
	return err == nil
}

func normalizeHash(hash string) string {
	return strings.ToLower(strings.TrimSpace(hash))
}

func normalizeAddress(address string) string {
	return strings.ToLower(strings.TrimSpace(address))
}

// validateBlockNumber validates and parses block number
func validateBlockNumber(blockStr string) (int64, error) {
	blockNumber, err := strconv.ParseInt(blockStr, 10, 64)
	if err != nil {
		return 0, ErrInvalidBlockNumber
	}
	if blockNumber < 0 {
		return 0, ErrInvalidBlockNumber
	}
	return blockNumber, nil
}

// validateChainID validates chain ID matches expected
func validateChainID(chainIDStr string, expectedChainID int) error {
	chainID, err := strconv.Atoi(chainIDStr)
	if err != nil {
		return fmt.Errorf("invalid chain ID format")
	}
	if chainID != expectedChainID {
		return fmt.Errorf("chain ID mismatch: expected %d, got %d", expectedChainID, chainID)
	}
	return nil
}

// validatePagination validates and normalizes pagination parameters
func validatePagination(pageStr, pageSizeStr string) (page, pageSize int, err error) {
	page = 1
	if pageStr != "" {
		page, err = strconv.Atoi(pageStr)
		if err != nil || page < 1 {
			return 0, 0, fmt.Errorf("invalid page number")
		}
	}

	pageSize = 20
	if pageSizeStr != "" {
		pageSize, err = strconv.Atoi(pageSizeStr)
		if err != nil || pageSize < 1 {
			return 0, 0, fmt.Errorf("invalid page size")
		}
		if pageSize > 100 {
			pageSize = 100 // Max page size
		}
	}

	return page, pageSize, nil
}

// writeValidationError writes a validation error response
func writeValidationError(w http.ResponseWriter, err error) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusBadRequest)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"error": map[string]interface{}{
			"code":    "VALIDATION_ERROR",
			"message": err.Error(),
		},
	})
}

// validateSearchQuery validates search query format
func validateSearchQuery(query string) (searchType string, value string, err error) {
	query = strings.TrimSpace(query)
	if query == "" {
		return "", "", fmt.Errorf("search query cannot be empty")
	}

	// Block number (numeric)
	if matched, _ := regexp.MatchString(`^\d+$`, query); matched {
		return "block", query, nil
	}

	// Address (0x + 40 hex chars)
	if matched, _ := regexp.MatchString(`^0x[a-fA-F0-9]{40}$`, query); matched {
		return "address", query, nil
	}

	// Transaction hash (0x + 64 hex chars)
	if matched, _ := regexp.MatchString(`^0x[a-fA-F0-9]{64}$`, query); matched {
		return "transaction", query, nil
	}

	return "", "", fmt.Errorf("invalid search query format")
}
