package task

import (
	"context"
	"fmt"

	larktask "github.com/larksuite/oapi-sdk-go/v3/service/task/v2"
)

type CreateSectionParam struct {
	Name         string
	ResourceType string
	ResourceID   string
	InsertBefore string
	InsertAfter  string
}

type UpdateSectionParam struct {
	SectionGUID  string
	Name         *string
	InsertBefore *string
	InsertAfter  *string
}

func (c *client) GetSection(ctx context.Context, id string) (*larktask.Section, error) {
	req := larktask.NewGetSectionReqBuilder().
		UserIdType("user_id").
		SectionGuid(id).
		Build()
	resp, err := c.larkCli.Task.V2.Section.Get(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("get section failed: %w", err)
	}
	if !resp.Success() {
		return nil, fmt.Errorf("get section failed: %s", resp.CodeError.String())
	}
	return resp.Data.Section, nil
}

func (c *client) CreateSection(ctx context.Context, param CreateSectionParam) (*string, error) {
	req := larktask.NewCreateSectionReqBuilder().
		UserIdType("user_id").
		InputSection(buildCreateSectionInput(param)).
		Build()
	resp, err := c.larkCli.Task.V2.Section.Create(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("create section failed: %w", err)
	}
	if !resp.Success() {
		return nil, fmt.Errorf("create section failed: %s", resp.CodeError.String())
	}
	return resp.Data.Section.Guid, nil
}

func (c *client) UpdateSection(ctx context.Context, param UpdateSectionParam) error {
	input, fields := buildUpdateSectionInput(param)
	if len(fields) == 0 {
		return nil
	}

	req := larktask.NewPatchSectionReqBuilder().
		UserIdType("user_id").
		SectionGuid(param.SectionGUID).
		Body(larktask.NewPatchSectionReqBodyBuilder().
			Section(input).
			UpdateFields(fields).
			Build()).
		Build()
	resp, err := c.larkCli.Task.V2.Section.Patch(ctx, req)
	if err != nil {
		return fmt.Errorf("update section failed: %w", err)
	}
	if !resp.Success() {
		return fmt.Errorf("update section failed: %s", resp.CodeError.String())
	}
	return nil
}

func (c *client) DeleteSection(ctx context.Context, id string) error {
	req := larktask.NewDeleteSectionReqBuilder().
		SectionGuid(id).
		Build()
	resp, err := c.larkCli.Task.V2.Section.Delete(ctx, req)
	if err != nil {
		return fmt.Errorf("delete section failed: %w", err)
	}
	if !resp.Success() {
		return fmt.Errorf("delete section failed: %s", resp.CodeError.String())
	}
	return nil
}

func (c *client) ListTaskOfSection(ctx context.Context, id string) ([]*larktask.TaskSummary, error) {
	req := larktask.NewTasksSectionReqBuilder().
		UserIdType("user_id").
		SectionGuid(id).
		PageSize(100).
		Build()
	iter, err := c.larkCli.Task.V2.Section.TasksByIterator(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("list task of section failed: %w", err)
	}

	tasks := make([]*larktask.TaskSummary, 0)
	for {
		hasNext, task, err := iter.Next()
		if err != nil {
			return nil, fmt.Errorf("list task of section failed: %w", err)
		}
		if !hasNext {
			return tasks, nil
		}
		tasks = append(tasks, task)
	}
}

func buildCreateSectionInput(param CreateSectionParam) *larktask.InputSection {
	sectionBuilder := larktask.NewInputSectionBuilder()
	if param.Name != "" {
		sectionBuilder.Name(param.Name)
	}
	if param.ResourceType != "" {
		sectionBuilder.ResourceType(param.ResourceType)
	}
	if param.ResourceID != "" {
		sectionBuilder.ResourceId(param.ResourceID)
	}
	if param.InsertBefore != "" {
		sectionBuilder.InsertBefore(param.InsertBefore)
	}
	if param.InsertAfter != "" {
		sectionBuilder.InsertAfter(param.InsertAfter)
	}
	return sectionBuilder.Build()
}

func buildUpdateSectionInput(param UpdateSectionParam) (*larktask.InputSection, []string) {
	sectionBuilder := larktask.NewInputSectionBuilder()
	fields := make([]string, 0, 3)

	if param.Name != nil {
		sectionBuilder.Name(*param.Name)
		fields = append(fields, "name")
	}
	if param.InsertBefore != nil {
		sectionBuilder.InsertBefore(*param.InsertBefore)
		fields = append(fields, "insert_before")
	}
	if param.InsertAfter != nil {
		sectionBuilder.InsertAfter(*param.InsertAfter)
		fields = append(fields, "insert_after")
	}

	return sectionBuilder.Build(), fields
}
