package exec

import (
	"context"
	"fmt"
	"net/url"
	"strings"

	"github.com/tidbcloud/AgentTeam/desktop/internal/wire/apiclient"
	"github.com/tidbcloud/AgentTeam/internal/core/domain"
)

type taskRemote struct {
	client  *apiclient.Client
	read    remoteReadTransport
	natural naturalMutationTransport
}

func (remote taskRemote) readTransport() remoteReadTransport {
	transport := remote.read
	transport.client = remote.client
	return transport
}

func (remote taskRemote) naturalTransport() naturalMutationTransport {
	transport := remote.natural
	transport.client = remote.client
	return transport
}

type taskCreateTransportRequest struct {
	Channel         string                    `json:"channel,omitempty"`
	Tasks           []taskDraft               `json:"tasks"`
	Parent          int                       `json:"parent,omitempty"`
	ParentTaskScope *domain.MessageScopeValue `json:"parentTaskScope,omitempty"`
	Target          string                    `json:"target,omitempty"`
}

type taskSetClaimTransportRequest struct {
	Channel string `json:"channel"`
	Numbers []int  `json:"numbers"`
	Claimed bool   `json:"claimed"`
}

type taskDetailTransport struct {
	Task               taskSummary         `json:"task"`
	ParentTask         *taskSummary        `json:"parentTask,omitempty"`
	AcceptanceCriteria []taskChecklistItem `json:"acceptanceCriteria,omitempty"`
	ReviewChecklist    []taskChecklistItem `json:"reviewChecklist,omitempty"`
	Subtasks           []taskSummary       `json:"subtasks,omitempty"`
	PinnedMessageRefs  []string            `json:"pinnedMessageRefs,omitempty"`
	RelevantURLs       []string            `json:"relevantURLs,omitempty"`
	WorkspaceRefs      []string            `json:"workspaceRefs,omitempty"`
}

func (detail taskDetailTransport) model() taskDetail {
	return taskDetail{
		Task:               detail.Task,
		ParentTask:         detail.ParentTask,
		AcceptanceCriteria: detail.AcceptanceCriteria,
		ReviewChecklist:    detail.ReviewChecklist,
		Subtasks:           detail.Subtasks,
		Messages:           detail.PinnedMessageRefs,
		URLs:               detail.RelevantURLs,
		Workspaces:         detail.WorkspaceRefs,
	}
}

type taskDetailTransportResult struct {
	Detail taskDetailTransport `json:"detail"`
}

func (a taskRemote) list(ctx context.Context, input taskListRequest) (taskListResult, error) {
	if err := requireRuntimeClient(a.client); err != nil {
		return taskListResult{}, err
	}
	query := url.Values{}
	query.Set("channel", strings.TrimSpace(input.Channel))
	if value := strings.TrimSpace(input.Status); value != "" {
		query.Set("status", value)
	}
	if input.Limit > 0 {
		query.Set("limit", fmt.Sprintf("%d", input.Limit))
	}
	if value := strings.TrimSpace(input.Query); value != "" {
		query.Set("query", value)
	}
	if value := strings.TrimSpace(input.Cursor); value != "" {
		query.Set("cursor", value)
	}
	if value := strings.TrimSpace(input.Sort); value != "" {
		query.Set("sort", value)
	}
	if input.IncludeSubtasks {
		query.Set("includeSubtasks", "true")
	}
	for _, filter := range input.Filters {
		if filter = strings.TrimSpace(filter); filter != "" {
			query.Add("quickFilters", filter)
		}
	}
	var result taskListResult
	return result, a.readTransport().get(ctx, a.client.AgentRuntimePath("/tasks?"+query.Encode()), &result)
}

func (a taskRemote) create(ctx context.Context, input taskCreateRequest) (taskCreateResult, error) {
	if err := requireRuntimeClient(a.client); err != nil {
		return taskCreateResult{}, err
	}
	target := strings.TrimSpace(input.Target)
	body := taskCreateTransportRequest{
		Channel:         taskBoardPart(input.Channel),
		Tasks:           input.Tasks,
		Parent:          input.Parent,
		ParentTaskScope: input.ParentTaskScope,
		Target:          target,
	}
	var result taskCreateResult
	return result, a.naturalTransport().post(ctx, a.client.AgentRuntimePath("/tasks"), body, &result)
}

func (a taskRemote) get(ctx context.Context, input taskGetRequest) (taskDetailResult, error) {
	if err := requireRuntimeClient(a.client); err != nil {
		return taskDetailResult{}, err
	}
	var response taskDetailTransportResult
	if err := a.readTransport().post(ctx, a.client.AgentRuntimePath("/tasks/get"), input, &response); err != nil {
		return taskDetailResult{}, err
	}
	return taskDetailResult{Detail: response.Detail.model()}, nil
}

func (a taskRemote) update(ctx context.Context, input taskUpdateRequest) (taskMutationResult, error) {
	return postTaskJSON[taskUpdateRequest, taskMutationResult](ctx, a, "/tasks/update", input)
}

func (a taskRemote) checkpoint(ctx context.Context, input taskCheckpointRequest) (taskMutationResult, error) {
	return postTaskJSON[taskCheckpointRequest, taskMutationResult](ctx, a, "/tasks/add-checkpoint", input)
}

func (a taskRemote) delete(ctx context.Context, input taskDeleteRequest) (taskDeleteResult, error) {
	return postTaskJSON[taskDeleteRequest, taskDeleteResult](ctx, a, "/tasks/delete", input)
}

func (a taskRemote) setClaim(ctx context.Context, input taskClaimRequest, claimed bool) (taskClaimResult, error) {
	body := taskSetClaimTransportRequest{Channel: input.Channel, Numbers: input.Numbers, Claimed: claimed}
	return postTaskJSON[taskSetClaimTransportRequest, taskClaimResult](ctx, a, "/tasks/set-claim", body)
}

func postTaskJSON[I, O any](ctx context.Context, remote taskRemote, suffix string, input I) (O, error) {
	var result O
	if err := requireRuntimeClient(remote.client); err != nil {
		return result, err
	}
	return result, remote.naturalTransport().post(ctx, remote.client.AgentRuntimePath(suffix), input, &result)
}

func taskBoardPart(target string) string {
	target = strings.TrimSpace(target)
	if strings.HasPrefix(target, "#") {
		if index := strings.IndexByte(target, ':'); index >= 0 {
			return target[:index]
		}
	}
	if strings.HasPrefix(target, "dm:@") {
		parts := strings.Split(target, ":")
		if len(parts) >= 2 {
			return strings.Join(parts[:2], ":")
		}
	}
	return target
}
