package api

import (
	"fmt"
	"net/http"
	"net/url"

	"gitlink.org.cn/cloudream/common/consts/errorcode"
	"gitlink.org.cn/cloudream/common/pkgs/iterator"
	"gitlink.org.cn/cloudream/common/sdks"
	"gitlink.org.cn/cloudream/common/utils/http2"
	"gitlink.org.cn/cloudream/common/utils/serder"
	clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types"
)

type PackageService struct {
	*Client
}

func (c *Client) Package() *PackageService {
	return &PackageService{c}
}

const PackageGetPath = "/package/get"

type PackageGetReq struct {
	PackageID clitypes.PackageID `form:"packageID" url:"packageID" binding:"required"`
}

func (r *PackageGetReq) MakeParam() *sdks.RequestParam {
	return sdks.MakeQueryParam(http.MethodGet, PackageGetPath, r)
}

type PackageGetResp struct {
	clitypes.Package
}

func (r *PackageGetResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (c *PackageService) Get(req PackageGetReq) (*PackageGetResp, error) {
	return JSONAPI(c.cfg, http.DefaultClient, &req, &PackageGetResp{})
}

const PackageGetByFullNamePath = "/package/getByFullName"

type PackageGetByFullName struct {
	BucketName  string `form:"bucketName" url:"bucketName" binding:"required"`
	PackageName string `form:"packageName" url:"packageName" binding:"required"`
}

func (r *PackageGetByFullName) MakeParam() *sdks.RequestParam {
	return sdks.MakeQueryParam(http.MethodGet, PackageGetByFullNamePath, r)
}

type PackageGetByFullNameResp struct {
	Package clitypes.Package `json:"package"`
}

func (r *PackageGetByFullNameResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (c *PackageService) GetByName(req PackageGetByFullName) (*PackageGetByFullNameResp, error) {
	return JSONAPI(c.cfg, http.DefaultClient, &req, &PackageGetByFullNameResp{})
}

const PackageCreatePath = "/package/create"

type PackageCreate struct {
	BucketID clitypes.BucketID `json:"bucketID"`
	Name     string            `json:"name"`
}

func (r *PackageCreate) MakeParam() *sdks.RequestParam {
	return sdks.MakeJSONParam(http.MethodPost, PackageCreatePath, r)
}

type PackageCreateResp struct {
	Package clitypes.Package `json:"package"`
}

func (r *PackageCreateResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (s *PackageService) Create(req PackageCreate) (*PackageCreateResp, error) {
	return JSONAPI(s.cfg, http.DefaultClient, &req, &PackageCreateResp{})
}

const PackageCreateLoadPath = "/package/createLoad"

type PackageCreateLoad struct {
	PackageCreateLoadInfo
	Files UploadObjectIterator `json:"-"`
}
type PackageCreateLoadInfo struct {
	BucketID   clitypes.BucketID      `json:"bucketID" binding:"required"`
	Name       string                 `json:"name" binding:"required"`
	LoadTo     []clitypes.UserSpaceID `json:"loadTo"`
	LoadToPath []string               `json:"loadToPath"`
}
type PackageCreateLoadResp struct {
	Package clitypes.Package  `json:"package"`
	Objects []clitypes.Object `json:"objects"`
}

func (c *PackageService) CreateLoad(req PackageCreateLoad) (*PackageCreateLoadResp, error) {
	url, err := url.JoinPath(c.cfg.URL, PackageCreateLoadPath)
	if err != nil {
		return nil, err
	}

	infoJSON, err := serder.ObjectToJSON(req)
	if err != nil {
		return nil, fmt.Errorf("upload info to json: %w", err)
	}

	resp, err := PostMultiPart(c.cfg, url,
		map[string]string{"info": string(infoJSON)},
		iterator.Map(req.Files, func(src *UploadingObject) (*http2.IterMultiPartFile, error) {
			return &http2.IterMultiPartFile{
				FieldName: "files",
				FileName:  src.Path,
				File:      src.File,
			}, nil
		}))
	if err != nil {
		return nil, err
	}

	codeResp, err := ParseJSONResponse[response[PackageCreateLoadResp]](resp)
	if err != nil {
		return nil, err
	}

	if codeResp.Code == errorcode.OK {
		return &codeResp.Data, nil
	}

	return nil, codeResp.ToError()
}

const PackageDeletePath = "/package/delete"

type PackageDelete struct {
	PackageID clitypes.PackageID `json:"packageID" binding:"required"`
}

func (r *PackageDelete) MakeParam() *sdks.RequestParam {
	return sdks.MakeJSONParam(http.MethodPost, PackageDeletePath, r)
}

type PackageDeleteResp struct{}

func (r *PackageDeleteResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (c *PackageService) Delete(req PackageDelete) error {
	return JSONAPINoData(c.cfg, http.DefaultClient, &req)
}

const PackageClonePath = "/package/clone"

type PackageClone struct {
	PackageID clitypes.PackageID `json:"packageID" binding:"required"`
	BucketID  clitypes.BucketID  `json:"bucketID" binding:"required"`
	Name      string             `json:"name" binding:"required"`
}

func (r *PackageClone) MakeParam() *sdks.RequestParam {
	return sdks.MakeJSONParam(http.MethodPost, PackageClonePath, r)
}

type PackageCloneResp struct {
	Package clitypes.Package `json:"package"`
}

func (r *PackageCloneResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (c *PackageService) Clone(req PackageClone) (*PackageCloneResp, error) {
	return JSONAPI(c.cfg, http.DefaultClient, &req, &PackageCloneResp{})
}

const PackageListBucketPackagesPath = "/package/listBucketPackages"

type PackageListBucketPackages struct {
	BucketID clitypes.BucketID `form:"bucketID" url:"bucketID" binding:"required"`
}

func (r *PackageListBucketPackages) MakeParam() *sdks.RequestParam {
	return sdks.MakeQueryParam(http.MethodGet, PackageListBucketPackagesPath, r)
}

type PackageListBucketPackagesResp struct {
	Packages []clitypes.Package `json:"packages"`
}

func (r *PackageListBucketPackagesResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (c *PackageService) ListBucketPackages(req PackageListBucketPackages) (*PackageListBucketPackagesResp, error) {
	return JSONAPI(c.cfg, http.DefaultClient, &req, &PackageListBucketPackagesResp{})
}

const PackageGetCachedStoragesPath = "/package/getCachedStorages"

type PackageGetCachedStoragesReq struct {
	PackageID clitypes.PackageID `form:"packageID" url:"packageID" binding:"required"`
}

func (r *PackageGetCachedStoragesReq) MakeParam() *sdks.RequestParam {
	return sdks.MakeQueryParam(http.MethodGet, PackageGetCachedStoragesPath, r)
}

/*
type PackageGetCachedStoragesResp struct {
	cdssdk.PackageCachingInfo
}

func (r *PackageGetCachedStoragesResp) ParseResponse(resp *http.Response) error {
	return sdks.ParseCodeDataJSONResponse(resp, r)
}

func (c *PackageService) GetCachedStorages(req PackageGetCachedStoragesReq) (*PackageGetCachedStoragesResp, error) {
	return JSONAPI(c.cfg, http.DefaultClient, &req, &PackageGetCachedStoragesResp{})
}
*/
