package client

import (
	"bytes"
	"compress/gzip"
	"io"
	"math/rand"
	"net/http"
	"net/url"
	"strings"

	"github.com/andybalholm/brotli"
	http2 "github.com/bogdanfinn/fhttp"
	tls_client "github.com/bogdanfinn/tls-client"
	"github.com/bogdanfinn/tls-client/profiles"
)

// TLSClient 使用 tls-client 模拟浏览器指纹的 HTTP 客户端
type TLSClient struct {
	client     tls_client.HttpClient
	userAgent  string
	chromeVer  string
	acceptLang string
}

// 语言偏好池
var languagePrefs = []string{
	"en-US,en;q=0.9",
	"en-GB,en;q=0.9,en-US;q=0.8",
	"de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
}

// New 创建一个新的 TLS 客户端
func New(proxyStr string) (*TLSClient, error) {
	jar := tls_client.NewCookieJar()
	chromeVer := "133"

	options := []tls_client.HttpClientOption{
		tls_client.WithTimeoutSeconds(60),
		tls_client.WithClientProfile(profiles.Chrome_133),
		tls_client.WithRandomTLSExtensionOrder(),
		tls_client.WithCookieJar(jar),
		tls_client.WithInsecureSkipVerify(),
	}

	if proxyStr != "" {
		options = append(options, tls_client.WithProxyUrl(proxyStr))
	}

	client, err := tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...)
	if err != nil {
		return nil, err
	}

	acceptLang := languagePrefs[rand.Intn(len(languagePrefs))]
	userAgent := generateUserAgent(chromeVer)

	return &TLSClient{
		client:     client,
		userAgent:  userAgent,
		chromeVer:  chromeVer,
		acceptLang: acceptLang,
	}, nil
}

// generateUserAgent 生成随机化的 User-Agent
func generateUserAgent(chromeVer string) string {
	winVersions := []string{
		"Windows NT 10.0; Win64; x64",
		"Windows NT 10.0; WOW64",
	}
	winVer := winVersions[rand.Intn(len(winVersions))]

	return "Mozilla/5.0 (" + winVer + ") AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + chromeVer + ".0.0.0 Safari/537.36"
}

// getDefaultHeaders 获取默认请求头
func (c *TLSClient) getDefaultHeaders() map[string]string {
	secChUa := `"Chromium";v="` + c.chromeVer + `", "Not(A:Brand";v="99", "Google Chrome";v="` + c.chromeVer + `"`

	return map[string]string{
		"User-Agent":                c.userAgent,
		"Accept":                    "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
		"Accept-Language":           c.acceptLang,
		"Accept-Encoding":           "gzip, deflate, br, zstd",
		"Cache-Control":             "max-age=0",
		"Sec-Ch-Ua":                 secChUa,
		"Sec-Ch-Ua-Mobile":          "?0",
		"Sec-Ch-Ua-Platform":        `"Windows"`,
		"Sec-Fetch-Dest":            "document",
		"Sec-Fetch-Mode":            "navigate",
		"Sec-Fetch-Site":            "none",
		"Sec-Fetch-User":            "?1",
		"Upgrade-Insecure-Requests": "1",
	}
}

// Do 执行 HTTP 请求
func (c *TLSClient) Do(req *http.Request) (*http.Response, error) {
	fhttpReq, err := http2.NewRequest(req.Method, req.URL.String(), req.Body)
	if err != nil {
		return nil, err
	}

	for key, value := range c.getDefaultHeaders() {
		if req.Header.Get(key) == "" {
			fhttpReq.Header.Set(key, value)
		}
	}

	for key, values := range req.Header {
		for _, value := range values {
			fhttpReq.Header.Set(key, value)
		}
	}

	resp, err := c.client.Do(fhttpReq)
	if err != nil {
		return nil, err
	}

	finalReq := req
	if resp.Request != nil && resp.Request.URL != nil {
		finalReq = &http.Request{
			Method: resp.Request.Method,
			URL:    (*url.URL)(resp.Request.URL),
			Header: http.Header(resp.Request.Header),
		}
	}

	stdResp := &http.Response{
		Status:           resp.Status,
		StatusCode:       resp.StatusCode,
		Proto:            resp.Proto,
		ProtoMajor:       resp.ProtoMajor,
		ProtoMinor:       resp.ProtoMinor,
		Header:           http.Header(resp.Header),
		Body:             resp.Body,
		ContentLength:    resp.ContentLength,
		TransferEncoding: resp.TransferEncoding,
		Close:            resp.Close,
		Uncompressed:     resp.Uncompressed,
		Request:          finalReq,
	}

	return stdResp, nil
}

// Get 执行 GET 请求
func (c *TLSClient) Get(urlStr string) (*http.Response, error) {
	req, err := http.NewRequest("GET", urlStr, nil)
	if err != nil {
		return nil, err
	}
	return c.Do(req)
}

// Post 执行 POST 请求
func (c *TLSClient) Post(urlStr string, contentType string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", urlStr, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", contentType)
	return c.Do(req)
}

// PostForm 执行 POST 表单请求
func (c *TLSClient) PostForm(urlStr string, data url.Values) (*http.Response, error) {
	return c.Post(urlStr, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

// PostJSON 执行 POST JSON 请求
func (c *TLSClient) PostJSON(urlStr string, body io.Reader) (*http.Response, error) {
	return c.Post(urlStr, "application/json", body)
}

// GetCookie 获取指定 URL 的 Cookie
func (c *TLSClient) GetCookie(urlStr string, name string) string {
	u, err := url.Parse(urlStr)
	if err != nil {
		return ""
	}
	cookies := c.client.GetCookies(u)
	for _, cookie := range cookies {
		if cookie.Name == name {
			return cookie.Value
		}
	}
	return ""
}

// SetCookie 设置 Cookie
func (c *TLSClient) SetCookie(urlStr string, cookie *http.Cookie) {
	u, err := url.Parse(urlStr)
	if err != nil {
		return
	}
	c.client.SetCookies(u, []*http2.Cookie{
		{
			Name:   cookie.Name,
			Value:  cookie.Value,
			Path:   cookie.Path,
			Domain: cookie.Domain,
		},
	})
}

// ReadBody 读取响应体并自动处理压缩
func ReadBody(resp *http.Response) ([]byte, error) {
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	switch resp.Header.Get("Content-Encoding") {
	case "gzip":
		gzReader, err := gzip.NewReader(bytes.NewReader(data))
		if err != nil {
			return data, nil
		}
		defer gzReader.Close()
		return io.ReadAll(gzReader)
	case "br":
		return io.ReadAll(brotli.NewReader(bytes.NewReader(data)))
	}

	return data, nil
}

// ReadBodyString 读取响应体为字符串
func ReadBodyString(resp *http.Response) (string, error) {
	body, err := ReadBody(resp)
	if err != nil {
		return "", err
	}
	return string(body), nil
}
