package hcaptcha

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"tm/pkg/logger"
)

const (
	// DefaultVerifyURL is the default hCaptcha verification endpoint
	DefaultVerifyURL = "https://hcaptcha.com/siteverify"
	// DefaultTimeout is the default timeout for hCaptcha verification requests
	DefaultTimeout = 10 * time.Second
)

// Verifier handles hCaptcha token verification
type Verifier interface {
	Verify(token string, remoteIP string) (*VerificationResponse, error)
}

// Config holds configuration for hCaptcha verification
type Config struct {
	SecretKey string        `env:"HCAPTCHA_SECRET_KEY"`
	VerifyURL string        `env:"HCAPTCHA_VERIFY_URL"`
	Timeout   time.Duration `env:"HCAPTCHA_TIMEOUT"`
}

// VerificationResponse represents the response from hCaptcha verification API
type VerificationResponse struct {
	Success     bool     `json:"success"`
	ChallengeTS string   `json:"challenge_ts,omitempty"`
	Hostname    string   `json:"hostname,omitempty"`
	Credit      bool     `json:"credit,omitempty"`
	ErrorCodes  []string `json:"error-codes,omitempty"`
}

// verifier implements the Verifier interface
type verifier struct {
	secretKey string
	verifyURL string
	timeout   time.Duration
	logger    logger.Logger
	client    *http.Client
}

// NewVerifier creates a new hCaptcha verifier
func NewVerifier(config *Config, log logger.Logger) Verifier {
	verifyURL := config.VerifyURL
	if verifyURL == "" {
		verifyURL = DefaultVerifyURL
	}

	timeout := config.Timeout
	if timeout == 0 {
		timeout = DefaultTimeout
	}

	return &verifier{
		secretKey: config.SecretKey,
		verifyURL: verifyURL,
		timeout:   timeout,
		logger:    log,
		client: &http.Client{
			Timeout: timeout,
		},
	}
}

// Verify verifies an hCaptcha token with the hCaptcha API
func (v *verifier) Verify(token string, remoteIP string) (*VerificationResponse, error) {
	if token == "" {
		return &VerificationResponse{
			Success:    false,
			ErrorCodes: []string{"missing-input-response"},
		}, fmt.Errorf("hCaptcha token is required")
	}

	// Prepare form data
	data := url.Values{}
	data.Set("secret", v.secretKey)
	data.Set("response", token)
	if remoteIP != "" {
		data.Set("remoteip", remoteIP)
	}

	// Create request with form data in body
	req, err := http.NewRequest("POST", v.verifyURL, strings.NewReader(data.Encode()))
	if err != nil {
		v.logger.Error("Failed to create hCaptcha verification request", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to create verification request: %w", err)
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	// Make request
	resp, err := v.client.Do(req)
	if err != nil {
		v.logger.Error("Failed to verify hCaptcha token", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to verify token: %w", err)
	}
	defer resp.Body.Close()

	// Read response body
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		v.logger.Error("Failed to read hCaptcha verification response", map[string]interface{}{
			"error": err.Error(),
		})
		return nil, fmt.Errorf("failed to read verification response: %w", err)
	}

	// Parse response
	var verificationResponse VerificationResponse
	if err := json.Unmarshal(body, &verificationResponse); err != nil {
		v.logger.Error("Failed to parse hCaptcha verification response", map[string]interface{}{
			"error":  err.Error(),
			"body":   string(body),
			"status": resp.StatusCode,
		})
		return nil, fmt.Errorf("failed to parse verification response: %w", err)
	}

	// Log verification result
	if verificationResponse.Success {
		v.logger.Debug("hCaptcha token verified successfully", map[string]interface{}{
			"hostname": verificationResponse.Hostname,
		})
	} else {
		v.logger.Warn("hCaptcha token verification failed", map[string]interface{}{
			"error_codes": verificationResponse.ErrorCodes,
		})
	}

	return &verificationResponse, nil
}
