// Package ocr 提供验证码识别服务。
//
// TODO: 迁移到 common/clients/ocr.go
package ocr

import (
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"

	"git.listensoft.net/tool/jspkit/logger"
	"go.uber.org/zap"
)

// DefaultOcrOption 是默认的验证码识别服务配置
var DefaultOcrOption = OcrOption{
	User:   user,
	Pass:   pass,
	SoftId: softid,
}

const DefaultOcrURL = "http://upload.chaojiying.net"

// OcrOption 是验证码识别服务的配置
type OcrOption struct {
	User   string
	Pass   string
	SoftId string
}

// NewDefaultOcrClient 使用默认参数创建客户端
func NewDefaultOcrClient() OcrClient {
	return OcrClient{
		Option:  DefaultOcrOption,
		Client:  http.DefaultClient,
		Logger:  logger.GetLogger(),
		BaseURL: DefaultOcrURL,
	}
}

// OcrClient 是超级鹰验证码识别接口客户端。
// 文档链接: https://www.chaojiying.com/api-5.html
type OcrClient struct {
	Option  OcrOption    // 接口授权相关
	Client  *http.Client // HTTP 客户端
	Logger  *zap.Logger  // 日志
	BaseURL string       // 服务地址
}

// 验证码识别，传入图片路径。
func (c OcrClient) GetCaptchaCodePath(ctx context.Context, imgPath string) (string, error) {
	bstr, err := base64Img(imgPath)
	if err != nil {
		return "", err
	}
	return c.GetCaptchaCode(ctx, bstr)
}

// 验证码识别，传入 "data:image/jpg;base64,xxx" 格式的 url。
// 该 url 一般为 img 标签的 src 属性。不校验传入的 url 是否合法。
func (c OcrClient) GetCaptchaCodeURL(ctx context.Context, b64 string) (string, error) {
	_, bstr, _ := strings.Cut(b64, ",")
	return c.GetCaptchaCode(ctx, bstr)
}

// 验证码识别，传入 base64 编码的图片。
// 文档链接: https://www.chaojiying.com/price.html
func (c OcrClient) GetCaptchaCode(ctx context.Context, bstr string) (string, error) {
	u, err := url.Parse(c.BaseURL)
	if err != nil {
		return "", err
	}
	u = u.JoinPath("/Upload/Processing.php")

	param := make(url.Values)
	param.Set("user", c.Option.User)
	param.Set("pass", c.Option.Pass)
	param.Set("softid", c.Option.SoftId)
	param.Set("codetype", "1902")
	param.Set("file_base64", bstr)
	params := param.Encode()

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), strings.NewReader(params))
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := c.Client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	var rs Result
	err = json.Unmarshal(body, &rs)
	if err != nil {
		return "", err
	}
	if rs.ErrNo != 0 {
		c.Logger.Error("识别报错", zap.ByteString("body", body))
		return "", err
	}
	c.Logger.Debug("识别结果", zap.String("picStr", rs.PicStr))
	return rs.PicStr, nil
}
