package exec

import (
	"context"
	"strings"
)

type projectListRequest struct {
	Limit  int    `json:"limit,omitempty" jsonschema:"minimum=1,maximum=100"`
	Cursor string `json:"cursor,omitempty" jsonschema:"maxLength=512"`
}

type projectInfoDTO 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 projectListResponse struct {
	Projects   []projectInfoDTO `json:"projects"`
	HasMore    bool             `json:"hasMore"`
	NextCursor string           `json:"nextCursor,omitempty"`
}

var projectListSpec = actionSpec[projectListRequest, projectListResponse]{
	Meta: actionMeta{
		Domain:      "project",
		Name:        "list",
		Summary:     "list Projects you can see",
		Description: "List all Projects the caller can see in the current workspace.",
		Permission:  permissionReadOnly,
	},
	Examples: []actionExample[projectListRequest]{
		{Title: "first or next page", Input: projectListRequest{Limit: 20, Cursor: "<nextCursor>"}},
	},
}

type projectCreateRequestDTO struct {
	RootPath    string `json:"rootPath" jsonschema:"minLength=1,pattern=.*\\S.*"`
	Name        string `json:"name" jsonschema:"minLength=1,pattern=.*\\S.*"`
	Description string `json:"description,omitempty"`
	Visibility  string `json:"visibility,omitempty" jsonschema:"enum=private,enum=workspace"`
}

type projectCreateResponse struct {
	Project projectInfoDTO `json:"project"`
}

var projectCreateSpec = actionSpec[projectCreateRequestDTO, projectCreateResponse]{
	Meta: actionMeta{
		Domain:      "project",
		Name:        "create",
		Summary:     "create a Project anchored at a repo root",
		Description: "Create a Project in the current workspace, anchored at an absolute repository root path.",
		Permission:  permissionAgentScopedMutation,
	},
	Examples: []actionExample[projectCreateRequestDTO]{
		{Title: "private project", Input: projectCreateRequestDTO{RootPath: "/Users/me/repo", Name: "my-project"}},
	},
}

type projectDeleteRequest struct {
	ID string `json:"id" jsonschema:"minLength=1,pattern=.*\\S.*"`
}

type projectDeleteResponse struct {
	ID string `json:"id"`
}

var projectDeleteSpec = actionSpec[projectDeleteRequest, projectDeleteResponse]{
	Meta: actionMeta{
		Domain:      "project",
		Name:        "delete",
		Summary:     "delete a Project by id",
		Description: "Delete a Project by ID. Repository files and Reviews are preserved.",
		Permission:  permissionAgentScopedMutation,
	},
	Examples: []actionExample[projectDeleteRequest]{
		{Title: "by id", Input: projectDeleteRequest{ID: "prj_123"}},
	},
}

type projectHandler struct {
	read    remoteReadTransport
	natural naturalMutationTransport
}

func (handler projectHandler) list(ctx context.Context, request actionScopedJSON[projectListRequest]) (actionResult[projectListResponse], error) {
	input := request.Body
	if input.Limit <= 0 {
		input.Limit = 20
	}
	if input.Limit > 100 {
		input.Limit = 100
	}
	input.Cursor = strings.TrimSpace(input.Cursor)
	page, err := (projectRemote{client: request.Authorized.Server, read: handler.read, natural: handler.natural}).listPage(ctx, input)
	if err != nil {
		return actionResult[projectListResponse]{}, classifyAPIError(err, "list projects failed")
	}
	if page.Projects == nil {
		page.Projects = []projectInfo{}
	}
	items := make([]projectInfoDTO, 0, len(page.Projects))
	for _, project := range page.Projects {
		items = append(items, projectInfoDTO(project))
	}
	return actionResult[projectListResponse]{
		Data: projectListResponse{Projects: items, HasMore: page.HasMore, NextCursor: page.NextCursor}, Text: listSummary(page.Projects),
	}, nil
}

func (handler projectHandler) create(ctx context.Context, request actionScopedJSON[projectCreateRequestDTO]) (actionResult[projectCreateResponse], error) {
	body := request.Body
	if strings.TrimSpace(body.RootPath) == "" {
		return actionResult[projectCreateResponse]{}, NewError(CodeValidation, "rootPath is required")
	}
	if strings.TrimSpace(body.Name) == "" {
		return actionResult[projectCreateResponse]{}, NewError(CodeValidation, "name is required")
	}
	project, err := (projectRemote{client: request.Authorized.Server, read: handler.read, natural: handler.natural}).create(
		ctx,
		projectCreateRequest(body),
	)
	if err != nil {
		return actionResult[projectCreateResponse]{}, classifyAPIError(err, "create project failed")
	}
	return actionResult[projectCreateResponse]{
		Data: projectCreateResponse{Project: projectInfoDTO(project)},
		Text: "Created project: " + project.ID,
	}, nil
}

func (handler projectHandler) delete(ctx context.Context, request actionScopedJSON[projectDeleteRequest]) (actionResult[projectDeleteResponse], error) {
	id := strings.TrimSpace(request.Body.ID)
	if id == "" {
		return actionResult[projectDeleteResponse]{}, NewError(CodeValidation, "id is required")
	}
	if err := (projectRemote{client: request.Authorized.Server, read: handler.read, natural: handler.natural}).delete(ctx, id); err != nil {
		return actionResult[projectDeleteResponse]{}, classifyAPIError(err, "delete project failed")
	}
	return actionResult[projectDeleteResponse]{
		Data: projectDeleteResponse{ID: id}, Text: "Deleted project: " + id,
	}, nil
}
