// nolint
package bce

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"errors"
	"hash/crc32"
	"os"
	"runtime"
	"strconv"
	"strings"
	"testing"

	"github.com/baidubce/bce-sdk-go/http"
	"github.com/baidubce/bce-sdk-go/util"
)

type mockFile struct {
	*os.File
	seekError  error
	readError  error
	closeError error
}

func currentFileName() string {
	_, file, _, _ := runtime.Caller(0)
	return file
}

func TestNewBody(t *testing.T) {
	// prepare parameters
	str1 := "body string"
	hasher1 := md5.New()
	n, _ := hasher1.Write([]byte(str1))
	ExpectEqual(t, len(str1), n)
	md5Str1 := base64.StdEncoding.EncodeToString(hasher1.Sum(nil))

	// case1: NewBodyFromBytesV2
	body2, err := NewBodyFromBytesV2([]byte(str1), true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, len(str1), body2.Size())
	ExpectEqual(t, md5Str1, body2.ContentMD5())
	body21, err := NewBodyFromBytes([]byte(str1))
	ExpectEqual(t, nil, err)
	ExpectEqual(t, len(str1), body21.Size())
	ExpectEqual(t, md5Str1, body21.ContentMD5())

	// case2: NewBodyFromStringV2
	body3, err := NewBodyFromStringV2(str1, true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, len(str1), body3.Size())
	ExpectEqual(t, md5Str1, body3.ContentMD5())
	body31, err := NewBodyFromString(str1)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, len(str1), body31.Size())
	ExpectEqual(t, md5Str1, body31.ContentMD5())

	// case3: NewBodyFromFileV2
	file4, err := os.Open(currentFileName())
	ExpectEqual(t, nil, err)
	fileInfo4, err := file4.Stat()
	ExpectEqual(t, nil, err)
	body4, err := NewBodyFromFileV2(currentFileName(), true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, fileInfo4.Size(), body4.Size())
	body41, err := NewBodyFromFile(currentFileName())
	ExpectEqual(t, nil, err)
	ExpectEqual(t, fileInfo4.Size(), body41.Size())

	// case4: NewBodyFromSectionFileV2
	offset := int64(0)
	size := fileInfo4.Size() / 2
	body5, err := NewBodyFromSectionFileV2(file4, offset, size, true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, size, body5.Size())
	body51, err := NewBodyFromSectionFileV2(file4, offset, size, true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, size, body51.Size())

	// case5: NewBodyFromSizedReaderV2
	data6 := "this is a string for testing NewBodyFromSizedReaderV2"
	hasher6 := md5.New()
	n6, _ := hasher6.Write([]byte(data6))
	ExpectEqual(t, len(data6), n6)
	md5Str6 := base64.StdEncoding.EncodeToString(hasher6.Sum(nil))
	body6, err := NewBodyFromSizedReaderV2(bytes.NewBufferString(data6), int64(len(data6)), true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, len(data6), body6.Size())
	ExpectEqual(t, md5Str6, body6.ContentMD5())
	body61, err := NewBodyFromSizedReaderV2(bytes.NewBufferString(data6), int64(len(data6)), true)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, len(data6), body61.Size())
	ExpectEqual(t, md5Str6, body61.ContentMD5())

	// case6: NewBodyFromReader/ NewBodyFromReaderV2
	dataStr := "data string"
	dataReader := bytes.NewReader([]byte(dataStr))
	body62, err := NewBodyFromReader(dataReader, int64(len(dataStr)))
	trasferBody62, _ := body62.Stream().(*TeeReadNopCloser)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, nil, trasferBody62)
	body63, err := NewBodyFromReaderV2(dataReader, int64(len(dataStr)))
	_, ok := body63.Stream().(*TeeReadNopCloser)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, true, ok)
}

func TestBodyMethod(t *testing.T) {
	bodyStr := "this is a stirng fot testing the method of bce body."
	//case0: member methods
	body0 := &Body{}
	bodyStream := NewTeeReadNopCloser(bytes.NewBufferString(bodyStr))
	body0.SetStream(bodyStream)
	ExpectEqual(t, bodyStream, body0.Stream())
	body0.SetSize(int64(len(bodyStr)))
	ExpectEqual(t, len(bodyStr), body0.Size())
	crc32cHasher := crc32.New(crc32.MakeTable(crc32.Castagnoli))
	body0.SetWriter(crc32cHasher)
	ExpectEqual(t, crc32cHasher, body0.Writer())
	body0.SetContentMD5("md5Str string")
	ExpectEqual(t, "md5Str string", body0.ContentMD5())
	buf := make([]byte, len(bodyStr))
	n, err := body0.Read(buf)
	ExpectEqual(t, len(bodyStr), n)
	ExpectEqual(t, nil, err)
	ExpectEqual(t, crc32cHasher.Sum32(), body0.Crc32())
	ExpectEqual(t, nil, body0.Close())
}

func TestBceRequest(t *testing.T) {
	req := &BceRequest{}
	req.BuildHttpRequest()
	ExpectEqual(t, true, req.RequestId() != "")
	reqId := util.NewRequestId()
	req.SetRequestId(reqId)
	ExpectEqual(t, reqId, req.RequestId())
	cliErr := NewBceClientError("msg string")
	req.SetClientError(cliErr)
	ExpectEqual(t, cliErr, req.ClientError())
	body, err := NewBodyFromString("str string")
	ExpectEqual(t, nil, err)
	req.SetBody(body)
	ExpectEqual(t, req.Request.Body(), body)
	ExpectEqual(t, req.Request.Header(http.CONTENT_MD5), body.ContentMD5())
	ExpectEqual(t, req.Request.Header(http.CONTENT_LENGTH), strconv.FormatInt(body.Size(), 10))
	ExpectEqual(t, true, strings.Contains(req.String(), cliErr.Error()))
	bodyV2, err := NewBodyFromStringV2("str string", true)
	ExpectEqual(t, nil, err)
	req.SetBody(bodyV2)
	ExpectEqual(t, req.Request.Body(), bodyV2.Stream())
}

// TestNewBodyFromFileV2_FileOpenError 是用于测试 NewBodyFromFileV2_FileOpenError
// generated by Comate
func TestNewBodyFromFileV2_FileOpenError(t *testing.T) {
	// 使用不存在的文件路径触发文件打开错误
	_, err := NewBodyFromFileV2("/path/to/nonexistent/file.txt", false)
	if err == nil {
		t.Error("Expected error when opening non-existent file, but got nil")
	}
}

// TestNewBodyFromSizedReaderV2_NegativeSizeCopySuccess 是用于测试 NewBodyFromSizedReaderV2_NegativeSizeCopySuccess
// generated by Comate
func TestNewBodyFromSizedReaderV2_NegativeSizeCopySuccess(t *testing.T) {
	reader := strings.NewReader("test content")
	body, err := NewBodyFromSizedReaderV2(reader, -1, false)

	if err != nil {
		t.Errorf("Expected no error, but got %v", err)
	}
	if body == nil {
		t.Error("Expected non-nil body")
	}
	if body.size != int64(len("test content")) {
		t.Errorf("Expected size %d, but got %d", len("test content"), body.size)
	}
}

// TestNewBodyFromSizedReaderV2_SizeGreaterThanActual 是用于测试 NewBodyFromSizedReaderV2_SizeGreaterThanActual
// generated by Comate
func TestNewBodyFromSizedReaderV2_SizeGreaterThanActual(t *testing.T) {
	reader := strings.NewReader("short")
	body, err := NewBodyFromSizedReaderV2(reader, 10, false)

	if err == nil {
		t.Error("Expected 'size is great than reader actual size' error, but got nil")
	}
	if body != nil {
		t.Error("Expected nil body when size is greater than actual content")
	}
}

// TestNewBodyFromSectionFileV2_MD5CalculationError 是用于测试 NewBodyFromSectionFileV2_MD5CalculationError
// generated by Comate
func TestNewBodyFromSectionFileV2_MD5CalculationError(t *testing.T) {
	tmpfile, err := os.CreateTemp("", "testfile")
	if err != nil {
		t.Fatalf("创建临时文件失败: %v", err)
	}
	defer os.Remove(tmpfile.Name())
	defer tmpfile.Close()
	_, err = tmpfile.WriteString("test data")
	if err != nil {
		t.Fatalf("写入测试数据失败: %v", err)
	}
	mockFile := &mockFile{
		File:      tmpfile,
		readError: errors.New("read error"),
	}
	_, err = NewBodyFromSectionFileV2(mockFile.File, 0, 10, true)
	if err == nil {
		t.Error("期望返回MD5计算错误，但未返回错误")
	}
}
