package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"
)

/*
=============================================================
  极验识别 Demo (Go版)

  功能说明：
  提交极验验证码识别任务（支持三代/四代）
  极验识别为异步流程：先提交任务获取 resultid，再轮询查询结果

  使用方法：
  1. 确保已安装 Go 1.18 或更高版本
  2. 将下方的配置参数替换为你自己的值
  3. 运行脚本：go run recognize_geetest.go
=============================================================
*/

const (
	APPKEY       = "你的appkey"
	GT           = "你获取到的gt值"
	CHALLENGE    = ""
	ITEMID       = "0"
	REFERER      = ""
	PROXY        = ""
	DEVKEY       = ""
	SDK          = ""
	GIVEN        = ""
	HOST         = ""
	USERAGENT    = ""
	APIBase      = "http://api.ttocr.com/api"
	PollInterval = 2 * time.Second
	MaxPollTime  = 60 * time.Second
)

func postForm(endpoint string, values url.Values, timeout time.Duration) (map[string]interface{}, error) {
	client := &http.Client{Timeout: timeout}
	resp, err := client.PostForm(endpoint, values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, err
	}

	return result, nil
}

func submitTask() (string, error) {
	fmt.Println("==================================================")
	fmt.Println("[提交任务] 正在提交极验识别任务...")
	fmt.Println("==================================================")

	values := url.Values{}
	values.Set("appkey", APPKEY)
	values.Set("gt", GT)
	values.Set("itemid", ITEMID)
	if CHALLENGE != "" {
		values.Set("challenge", CHALLENGE)
	}
	if REFERER != "" {
		values.Set("referer", REFERER)
	}
	if PROXY != "" {
		values.Set("proxy", PROXY)
	}
	if DEVKEY != "" {
		values.Set("devkey", DEVKEY)
	}
	if SDK != "" {
		values.Set("sdk", SDK)
	}
	if GIVEN != "" {
		values.Set("given", GIVEN)
	}
	if HOST != "" {
		values.Set("host", HOST)
	}
	if USERAGENT != "" {
		values.Set("userAgent", USERAGENT)
	}

	fmt.Printf("[请求参数] gt=%s\n", GT)
	fmt.Printf("[请求参数] itemid=%s\n", ITEMID)

	result, err := postForm(APIBase+"/recognize", values, 30*time.Second)
	if err != nil {
		return "", err
	}

	pretty, _ := json.MarshalIndent(result, "", "  ")
	fmt.Printf("[提交响应] %s\n", string(pretty))

	if status, ok := result["status"].(float64); ok && status == 1 {
		resultID, _ := result["resultid"].(string)
		fmt.Printf("[成功] 任务提交成功！resultid=%s\n", resultID)
		return resultID, nil
	}

	return "", fmt.Errorf("任务提交失败：%v", result["msg"])
}

func queryResult(resultID string) error {
	fmt.Println("\n==================================================")
	fmt.Println("[查询结果] 正在轮询识别结果...")
	fmt.Printf("[查询结果] 轮询间隔：%d秒，最大等待：%d秒\n", int(PollInterval.Seconds()), int(MaxPollTime.Seconds()))
	fmt.Println("==================================================")

	startedAt := time.Now()
	for {
		if time.Since(startedAt) > MaxPollTime {
			return fmt.Errorf("已等待%d秒，识别超时，请稍后重试", int(MaxPollTime.Seconds()))
		}

		time.Sleep(PollInterval)

		values := url.Values{}
		values.Set("appkey", APPKEY)
		values.Set("resultid", resultID)

		result, err := postForm(APIBase+"/results", values, 30*time.Second)
		if err != nil {
			fmt.Printf("[异常] 查询请求出错：%v\n", err)
			continue
		}

		if status, ok := result["status"].(float64); ok && status == 1 {
			pretty, _ := json.MarshalIndent(result, "", "  ")
			fmt.Printf("\n[成功] 识别成功！耗时：%vms\n", result["time"])
			fmt.Printf("[识别结果] %v\n", result["data"])
			fmt.Printf("\n[完整响应] %s\n", string(pretty))
			return nil
		}

		fmt.Printf("[等待中] 第%d秒 - %v\n", int(time.Since(startedAt).Seconds()), result["msg"])
	}
}

func main() {
	fmt.Println("************************************************************")
	fmt.Println("  极验识别 Demo (Go版)")
	fmt.Println("************************************************************")

	if APPKEY == "你的appkey" {
		fmt.Println("\n[错误] 请先在代码顶部的配置区域填写你的 APPKEY")
		os.Exit(1)
	}
	if GT == "你获取到的gt值" {
		fmt.Println("\n[错误] 请先在代码顶部的配置区域填写 GT 值")
		os.Exit(1)
	}
	if ITEMID == "0" {
		fmt.Println("\n[错误] 请先在代码顶部的配置区域填写 ITEMID（项目类型）")
		os.Exit(1)
	}

	resultID, err := submitTask()
	if err != nil {
		fmt.Printf("[失败] %v\n", err)
		os.Exit(1)
	}

	if err := queryResult(resultID); err != nil {
		fmt.Printf("[失败] %v\n", err)
		os.Exit(1)
	}

	fmt.Println("\n==================================================")
	fmt.Println("[完成] 识别执行完毕")
	fmt.Println("==================================================")
}
