//go:generate ${GOBIN}/mockgen -destination meeting_mock.go -package=meeting ${GO_MODULE}/infra/lark/client/meeting Meeting
package meeting

import (
	"context"
	"fmt"
	"strconv"
	"time"

	lark "github.com/larksuite/oapi-sdk-go/v3"
	larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
	larkvc "github.com/larksuite/oapi-sdk-go/v3/service/vc/v1"
)

type GetMeetingParam struct {
	MeetingID          string
	WithParticipants   bool
	WithMeetingAbility bool
}

type Meeting interface {
	ListMeetingByNumber(ctx context.Context, number string, start time.Time, end time.Time) ([]*larkvc.Meeting /*only brief*/, error)
	GetMeeting(ctx context.Context, param GetMeetingParam) (*larkvc.Meeting, error)
	GetRecording(ctx context.Context, meetingID string, opts ...larkcore.RequestOptionFunc) (*larkvc.MeetingRecording, error)
}

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

type client struct {
	larkCli *lark.Client
}

func (c *client) ListMeetingByNumber(ctx context.Context, number string, start time.Time, end time.Time) ([]*larkvc.Meeting, error) {
	meetings := make([]*larkvc.Meeting, 0)
	pageToken := ""
	for {
		reqBuilder := larkvc.NewListByNoMeetingReqBuilder().
			MeetingNo(number).
			StartTime(strconv.FormatInt(start.Unix(), 10)).
			EndTime(strconv.FormatInt(end.Unix(), 10)).
			PageSize(100)
		if pageToken != "" {
			reqBuilder.PageToken(pageToken)
		}

		resp, err := c.larkCli.Vc.V1.Meeting.ListByNo(ctx, reqBuilder.Build())
		if err != nil {
			return nil, fmt.Errorf("list meeting by number failed: %w", err)
		}
		if !resp.Success() {
			return nil, fmt.Errorf("list meeting by number failed: %s", resp.CodeError.String())
		}

		meetings = append(meetings, resp.Data.MeetingBriefs...)
		if resp.Data.HasMore == nil || !*resp.Data.HasMore || resp.Data.PageToken == nil {
			return meetings, nil
		}
		pageToken = *resp.Data.PageToken
	}
}

func (c *client) GetMeeting(ctx context.Context, param GetMeetingParam) (*larkvc.Meeting, error) {
	reqBuilder := larkvc.NewGetMeetingReqBuilder().
		MeetingId(param.MeetingID).
		WithParticipants(param.WithParticipants).
		WithMeetingAbility(param.WithMeetingAbility).
		UserIdType("user_id")

	resp, err := c.larkCli.Vc.V1.Meeting.Get(ctx, reqBuilder.Build())
	if err != nil {
		return nil, fmt.Errorf("get meeting failed: %w", err)
	}
	if !resp.Success() {
		return nil, fmt.Errorf("get meeting failed: %s", resp.CodeError.String())
	}
	return resp.Data.Meeting, nil
}

func (c *client) GetRecording(ctx context.Context, meetingID string, opts ...larkcore.RequestOptionFunc) (*larkvc.MeetingRecording, error) {
	req := larkvc.NewGetMeetingRecordingReqBuilder().
		MeetingId(meetingID).
		Build()

	resp, err := c.larkCli.Vc.V1.MeetingRecording.Get(ctx, req, opts...)
	if err != nil {
		return nil, fmt.Errorf("get meeting recording failed: %w", err)
	}
	if !resp.Success() {
		return nil, fmt.Errorf("get meeting recording failed: %s", resp.CodeError.String())
	}
	return resp.Data.Recording, nil
}
