package exec

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

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

type projectInfo struct {
	ID          string `json:"id"`
	RootPath    string `json:"rootPath"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Visibility  string `json:"visibility,omitempty"`
	OwnerUserID string `json:"ownerUserId,omitempty"`
}

type projectCreateRequest struct {
	RootPath    string `json:"rootPath"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Visibility  string `json:"visibility,omitempty"`
}

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

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

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

type projectListTransportResponse struct {
	Projects   []projectInfo `json:"projects"`
	HasMore    bool          `json:"hasMore"`
	NextCursor string        `json:"nextCursor"`
}

type projectListPage struct {
	Projects   []projectInfo
	HasMore    bool
	NextCursor string
}

func (a projectRemote) projectPath(suffix string) (string, error) {
	if err := requireRuntimeClient(a.client); err != nil {
		return "", err
	}
	return a.client.AgentRuntimePath("/projects") + suffix, nil
}

func (a projectRemote) listPage(ctx context.Context, input projectListRequest) (projectListPage, error) {
	path, err := a.projectPath("")
	if err != nil {
		return projectListPage{}, err
	}
	values := url.Values{}
	if input.Limit > 0 {
		values.Set("limit", fmt.Sprintf("%d", input.Limit))
	}
	if cursor := strings.TrimSpace(input.Cursor); cursor != "" {
		values.Set("cursor", cursor)
	}
	if encoded := values.Encode(); encoded != "" {
		path += "?" + encoded
	}
	var resp projectListTransportResponse
	if err := a.readTransport().get(ctx, path, &resp); err != nil {
		return projectListPage{}, err
	}
	if resp.Projects == nil {
		resp.Projects = []projectInfo{}
	}
	return projectListPage{Projects: resp.Projects, HasMore: resp.HasMore, NextCursor: strings.TrimSpace(resp.NextCursor)}, nil
}

// list preserves the small-call helper used by older Desktop callers while
// the Exec action uses listPage to retain continuation metadata.
func (a projectRemote) list(ctx context.Context) ([]projectInfo, error) {
	page, err := a.listPage(ctx, projectListRequest{})
	if err != nil {
		return nil, err
	}
	return page.Projects, nil
}

func (a projectRemote) create(ctx context.Context, req projectCreateRequest) (projectInfo, error) {
	path, err := a.projectPath("")
	if err != nil {
		return projectInfo{}, err
	}
	body := map[string]any{
		"rootPath": strings.TrimSpace(req.RootPath),
		"name":     strings.TrimSpace(req.Name),
	}
	if d := strings.TrimSpace(req.Description); d != "" {
		body["description"] = d
	}
	if v := strings.TrimSpace(req.Visibility); v != "" {
		body["visibility"] = v
	}
	var resp struct {
		Project projectInfo `json:"project"`
	}
	if err := a.naturalTransport().post(ctx, path, body, &resp); err != nil {
		return projectInfo{}, err
	}
	return resp.Project, nil
}

func (a projectRemote) delete(ctx context.Context, id string) error {
	path, err := a.projectPath("/" + url.PathEscape(id))
	if err != nil {
		return err
	}
	return a.naturalTransport().delete(ctx, path, nil)
}

func listSummary(projects []projectInfo) string {
	if len(projects) == 0 {
		return "No projects registered."
	}
	return fmt.Sprintf("Listed %d project%s.", len(projects), pluralS(len(projects)))
}

func pluralS(n int) string {
	if n == 1 {
		return ""
	}
	return "s"
}
