package im

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
	"github.com/tidbcloud/AgentTeam/internal/store/channel"
	"github.com/tidbcloud/AgentTeam/internal/store/taskboard"
)

const defaultScopeSnapshotMessageLimit = 30

type scopeSnapshotResponse struct {
	Messages               *dto.AppMessagePage                                           `json:"messages,omitempty"`
	Tasks                  *dto.TaskPageResponse                                         `json:"tasks,omitempty"`
	Members                *dto.ChannelMemberList                                        `json:"members,omitempty"`
	PrivateAgentCapability *dto.ResolvePrivateAgentContextContributionCapabilityResponse `json:"privateAgentCapability,omitempty"`
}

type ScopeSnapshotHandler struct {
	access         ChannelAccessResolver
	messages       MessageStore
	channelMembers ChannelMemberStore
	taskBoard      ScopeSnapshotTaskBoard
}

func (h *ScopeSnapshotHandler) Get(r api.WorkspaceScopedRequest) (api.Response, error) {
	scopeID, err := routeScopeID(r)
	if err != nil {
		return api.Response{}, err
	}
	includes := parseScopeSnapshotIncludes(r.Gin.Query("include"))
	if len(includes) == 0 {
		includes["messages"] = true
	}
	// Members are a Channel-only snapshot projection. Use that existing query
	// signal to move authoritative Channel admission before every requested
	// private read without changing the generic message-only snapshot contract
	// used by threads, DMs, and service-account scopes.
	if includes["members"] {
		if h.access == nil {
			return api.Response{}, fmt.Errorf("scope snapshot channel access dependency is not configured")
		}
		access, err := h.access.ResolveChannelAccessForUser(r.Context(), r.UserID(), r.WorkspaceID(), scopeID)
		if err != nil {
			return api.Response{}, fmt.Errorf("resolve scope snapshot channel access: %w", err)
		}
		switch access.Status {
		case channel.ChannelAccessStatusJoined:
		case channel.ChannelAccessStatusPublicJoinable, channel.ChannelAccessStatusInaccessible:
			return api.Response{}, api.ErrForbidden
		case channel.ChannelAccessStatusNotFound:
			return api.Response{}, api.ErrNotFound
		default:
			return api.Response{}, fmt.Errorf("unsupported scope snapshot channel access status %q", access.Status)
		}
	}

	ctx := r.Context()
	user := r.User.User
	workspaceID := r.WorkspaceID()
	response := scopeSnapshotResponse{}

	if includes["messages"] {
		if h.messages == nil {
			return api.Response{}, api.NewHTTPError(http.StatusInternalServerError, "Internal server error")
		}
		limit, err := parseLimit(r.Gin.Query("messageLimit"), defaultScopeSnapshotMessageLimit, maxIMListLimit)
		if err != nil {
			return api.Response{}, err
		}
		messages, err := h.messages.ListMessagesForUser(ctx, user.ID, workspaceID, scopeID, limit, nil, nil)
		if err != nil {
			return api.Response{}, fmt.Errorf("list scope snapshot messages: %w", err)
		}
		converted := converter.ToAppMessagePage(messages)
		response.Messages = &converted
	}

	if includes["tasks"] {
		if h.taskBoard == nil {
			return api.Response{}, api.NewHTTPError(http.StatusNotImplemented, "scope snapshot tasks are not supported")
		}
		tasks, err := h.taskBoard.ListTasks(ctx, scopeSnapshotTaskListRequest(workspaceID, user.ID, user.Name, scopeID))
		if err != nil {
			return api.Response{}, fmt.Errorf("list scope snapshot tasks: %w", err)
		}
		response.Tasks = &dto.TaskPageResponse{Tasks: converter.ToTasksEmpty(tasks.Tasks)}
	}

	if includes["members"] {
		if h.channelMembers == nil {
			return api.Response{}, api.NewHTTPError(http.StatusNotImplemented, "scope snapshot members are not supported")
		}
		members, err := h.channelMembers.ChannelMembersForUser(ctx, user.ID, workspaceID, scopeID)
		if err != nil {
			return api.Response{}, fmt.Errorf("list scope snapshot members: %w", err)
		}
		converted := converter.ToChannelMemberList(members)
		response.Members = &converted
	}

	if includes["privateAgentCapability"] {
		if h.taskBoard == nil {
			return api.Response{}, api.NewHTTPError(http.StatusNotImplemented, "scope snapshot private-agent capability is not supported")
		}
		executionOwnerMemberID := strings.TrimSpace(r.Gin.Query("executionOwnerMemberId"))
		if executionOwnerMemberID != "" {
			capability, err := h.taskBoard.ResolvePrivateAgentContextContributionCapability(ctx, scopeSnapshotPrivateAgentCapabilityRequest(workspaceID, user.ID, user.Name, scopeID, executionOwnerMemberID))
			if err != nil {
				return api.Response{}, fmt.Errorf("resolve scope snapshot private-agent capability: %w", err)
			}
			converted := converter.ToResolvePrivateAgentContextContributionCapabilityResponse(capability)
			response.PrivateAgentCapability = &converted
		}
	}

	return api.OK(response), nil
}

func parseScopeSnapshotIncludes(raw string) map[string]bool {
	includes := make(map[string]bool)
	for _, part := range strings.Split(raw, ",") {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		includes[part] = true
	}
	return includes
}

func scopeSnapshotTaskListRequest(workspaceID string, userID string, userName string, scopeID string) taskboard.ListTasksRequest {
	return taskboard.ListTasksRequest{
		Context:         taskboard.NewUserServiceContext(workspaceID, userID, userName),
		Board:           taskboard.BoardRef{ChannelID: scopeID},
		IncludeSubtasks: false,
	}
}

func scopeSnapshotPrivateAgentCapabilityRequest(workspaceID string, userID string, userName string, scopeID string, executionOwnerMemberID string) taskboard.ResolvePrivateAgentContextContributionCapabilityRequest {
	return taskboard.ResolvePrivateAgentContextContributionCapabilityRequest{
		Context: taskboard.NewUserServiceContext(workspaceID, userID, userName),
		Scope: taskboard.TaskCollaboratorScopeRef{
			ScopeType:              "channel",
			ScopeID:                scopeID,
			ExecutionOwnerMemberID: executionOwnerMemberID,
		},
	}
}
