package task

import (
	"context"
	"fmt"

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

type Task interface {
	CreateTask(ctx context.Context, title string, description string, dueTime string, incidentUrl string, executors []string, followers []string) (*string, error)
	GetTask(ctx context.Context, id string) (*larktask.Task, error)
	UpdateTask(ctx context.Context, id string, title string, description string, dueTime string, incidentUrl string, executors []string, followers []string) error
	CompleteTask(ctx context.Context, id string) error
	DeleteTask(ctx context.Context, id string) error
}

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

type client struct {
	larkCli *lark.Client
}

func (c *client) CreateTask(ctx context.Context, title string, description string, dueTime string, incidentUrl string, executors []string, followers []string) (*string /*task id*/, error) {
	taskBuilder := larktask.NewTaskBuilder().
		Summary(title).
		Description(description).
		RichSummary(title).
		RichDescription(description).
		Origin(larktask.NewOriginBuilder().
			PlatformI18nName(`{"zh_cn": "devops incident", "en_us": "devops incident"}`).
			Href(larktask.NewHrefBuilder().
				Url(incidentUrl).
				Title("Open incident").
				Build()).
			Build()).
		CanEdit(true).
		CollaboratorIds(executors).
		FollowerIds(followers)
	if dueTime != "" {
		taskBuilder.Due(larktask.NewDueBuilder().
			Time(dueTime).
			Timezone(`Asia/Shanghai`).
			IsAllDay(false).
			Build())
	}
	req := larktask.NewCreateTaskReqBuilder().UserIdType("user_id").
		Task(taskBuilder.Build()).
		Build()

	resp, err := c.larkCli.Task.Task.Create(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("create task failed: %w", err)
	}
	if !resp.Success() {
		return nil, fmt.Errorf("create task failed: %s", resp.CodeError.String())
	}
	return resp.Data.Task.Id, nil
}

func (c *client) GetTask(ctx context.Context, id string) (*larktask.Task, error) {
	req := larktask.NewGetTaskReqBuilder().
		TaskId(id).Build()
	resp, err := c.larkCli.Task.Task.Get(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("get task failed: %w", err)
	}
	if !resp.Success() {
		return nil, fmt.Errorf("get task failed: %s", resp.CodeError.String())
	}
	return resp.Data.Task, nil
}

func (c *client) UpdateTask(ctx context.Context, id string, title string, description string, dueTime string, incidentUrl string, executors []string, followers []string) error {
	taskBuilder := larktask.NewTaskBuilder().
		RichSummary(title).
		RichDescription(description).
		Origin(larktask.NewOriginBuilder().
			PlatformI18nName(`{"zh_cn": "devops incident", "en_us": "devops incident"}`).
			Href(larktask.NewHrefBuilder().
				Url(incidentUrl).
				Title("Open incident").
				Build()).
			Build()).
		CanEdit(true).
		CollaboratorIds(executors).
		FollowerIds(followers)
	updateFields := []string{`rich_summary`, `rich_description`, `collaborator_ids`, `follower_ids`}
	if dueTime != "" {
		taskBuilder.Due(larktask.NewDueBuilder().
			Time(dueTime).
			Timezone(`Asia/Shanghai`).
			IsAllDay(false).
			Build())
		updateFields = append(updateFields, `due`)
	}
	req := larktask.NewPatchTaskReqBuilder().UserIdType("user_id").TaskId(id).
		Body(larktask.NewPatchTaskReqBodyBuilder().
			Task(taskBuilder.Build()).
			UpdateFields(updateFields).
			//UpdateFields([]string{`rich_summary`, `rich_description`, `due`, `origin`, `collaborator_ids`, `follower_ids`}).
			Build()).
		Build()
	resp, err := c.larkCli.Task.Task.Patch(ctx, req)
	if err != nil {
		return fmt.Errorf("get task failed: %w", err)
	}
	if !resp.Success() {
		return fmt.Errorf("get task failed: %s", resp.CodeError.String())
	}
	return nil
}

func (c *client) CompleteTask(ctx context.Context, id string) error {
	req := larktask.NewCompleteTaskReqBuilder().TaskId(id).Build()
	resp, err := c.larkCli.Task.Task.Complete(ctx, req)

	if err != nil {
		return fmt.Errorf("complete task failed: %w", err)
	}

	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return fmt.Errorf("complete task failed: %s", resp.CodeError.String())
	}
	return nil
}

func (c *client) DeleteTask(ctx context.Context, id string) error {
	req := larktask.NewDeleteTaskReqBuilder().TaskId(id).Build()
	resp, err := c.larkCli.Task.Task.Delete(ctx, req)

	if err != nil {
		return fmt.Errorf("delete task failed: %w", err)
	}

	if !resp.Success() {
		fmt.Println(resp.Code, resp.Msg, resp.RequestId())
		return fmt.Errorf("delete task failed: %s", resp.CodeError.String())
	}
	return nil
}
