//go:generate ${GOBIN}/mockgen -destination drive_mock.go -package=drive ${GO_MODULE}/infra/lark/client/drive Drive
package drive

import (
	"context"
	"fmt"

	lark "github.com/larksuite/oapi-sdk-go/v3"
	larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
	larkdrivev1 "github.com/larksuite/oapi-sdk-go/v3/service/drive/v1"
	larkdrivev2 "github.com/larksuite/oapi-sdk-go/v3/service/drive/v2"
)

// Reference: https://open.feishu.cn/document/server-docs/docs/permission/permission-public/patch-2
type DrivePermissionPatchParam struct {
	LinkShareEntity *string
	SecurityEntity  *string
}

// Reference: https://open.feishu.cn/document/server-docs/docs/permission/permission-member/create
type DrivePermissionMemberAddParam struct {
	Type             string // user, chat ...
	MemberType       string // openid, userid, groupid ...
	MemberID         string
	Perm             string // view, edit, full_access
	PermType         *string
	NeedNotification bool
}

type Drive interface {
	PatchPermission(ctx context.Context, token string, typ string, param DrivePermissionPatchParam, opts ...larkcore.RequestOptionFunc) error
	AddMember(ctx context.Context, token string, typ string, param DrivePermissionMemberAddParam, opts ...larkcore.RequestOptionFunc) error
}

func New(larkCli *lark.Client) Drive {
	return &client{
		larkCli: larkCli,
	}
}

type client struct {
	larkCli *lark.Client
}

func (c *client) PatchPermission(ctx context.Context, token string, typ string, param DrivePermissionPatchParam, opts ...larkcore.RequestOptionFunc) error {
	permissionBuilder := larkdrivev2.NewPermissionPublicBuilder()
	if param.LinkShareEntity != nil {
		permissionBuilder.LinkShareEntity(*param.LinkShareEntity)
	}
	if param.SecurityEntity != nil {
		permissionBuilder.SecurityEntity(*param.SecurityEntity)
	}

	req := larkdrivev2.NewPatchPermissionPublicReqBuilder().
		Token(token).
		Type(typ).
		PermissionPublic(permissionBuilder.Build()).
		Build()

	resp, err := c.larkCli.Drive.V2.PermissionPublic.Patch(ctx, req, opts...)
	if err != nil {
		return fmt.Errorf("patch drive permission failed: %w", err)
	}
	if !resp.Success() {
		return fmt.Errorf("patch drive permission failed: %s", resp.CodeError.String())
	}
	return nil
}

func (c *client) AddMember(ctx context.Context, token string, typ string, param DrivePermissionMemberAddParam, opts ...larkcore.RequestOptionFunc) error {
	memberBuilder := larkdrivev1.NewBaseMemberBuilder().
		Type(param.Type).
		MemberType(param.MemberType).
		MemberId(param.MemberID).
		Perm(param.Perm)
	if param.PermType != nil {
		memberBuilder.PermType(*param.PermType)
	}

	req := larkdrivev1.NewCreatePermissionMemberReqBuilder().
		Token(token).
		Type(typ).
		NeedNotification(param.NeedNotification).
		BaseMember(memberBuilder.Build()).
		Build()

	resp, err := c.larkCli.Drive.V1.PermissionMember.Create(ctx, req, opts...)
	if err != nil {
		return fmt.Errorf("add drive permission member failed: %w", err)
	}
	if !resp.Success() {
		return fmt.Errorf("add drive permission member failed: %s", resp.CodeError.String())
	}
	return nil
}
