package clients

import (
	"bytes"
	"context"
	"encoding/json"
	"io"
	"mime/multipart"
	"net/http"

	"go.uber.org/zap"
)

// PostScreenShotReq 申报截图上传参数
type PostScreenShotReq struct {
	Name   string // 文件名
	TaxNo  string // 税号
	Period string // 账期
}

// 申报截图上传响应
type PostScreenshotResp struct {
	Path string `json:"path"` // 截图路径
}

// FileClient 文件客户端
type FileClient struct {
	Client *http.Client // 客户端
	Logger *zap.Logger  // 日志
}

// PostScreenShotBytes 上传文件 返回上传的 url 参数 bs 为文件内容
func (c FileClient) PostScreenShotBytes(ctx context.Context, bs []byte, p PostScreenShotReq) (string, error) {
	return c.PostScreenShot(ctx, bytes.NewReader(bs), p)
}

// PostScreenShot 上传截图 返回上传的 url
func (c FileClient) PostScreenShot(ctx context.Context, r io.Reader, p PostScreenShotReq) (string, error) {
	var b bytes.Buffer
	mw, err := c.writeMultipart(&b, p, r)
	if err != nil {
		return "", err
	}

	const u = "https://file.listensoft.net/api/v1/uploadsbjt"
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, &b)
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-Type", mw.FormDataContentType())

	c.Logger.Debug("上传截图", zap.String("url", u), zap.String("name", p.Name))
	resp, err := c.Client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	bs, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	var response PostScreenshotResp
	err = json.Unmarshal(bs, &response)
	if err != nil {
		return "", err
	}
	path := response.Path
	c.Logger.Debug("上传截图成功", zap.String("name", p.Name), zap.String("path", path))
	return path, nil
}

func (c FileClient) writeMultipart(w io.Writer, param PostScreenShotReq, r io.Reader) (*multipart.Writer, error) {
	mw := multipart.NewWriter(w)
	err := writeFileFromReader(mw, "file", param.Name, r)
	if err != nil {
		return nil, err
	}
	err = mw.WriteField("tax_no", param.TaxNo)
	if err != nil {
		return nil, err
	}
	err = mw.WriteField("period", param.Period)
	if err != nil {
		return nil, err
	}
	err = mw.WriteField("type", "etax")
	if err != nil {
		return nil, err
	}
	err = mw.Close()
	if err != nil {
		return nil, err
	}
	return mw, nil
}
