package channel

import (
	"context"
	"net/http"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
	"github.com/tidbcloud/AgentTeam/internal/unread"
)

// ChannelLifecycleAppStore owns channel lifecycle and ownership mutations.
type ChannelLifecycleAppStore interface {
	ArchiveChannelForUser(ctx context.Context, userID string, workspaceID string, channelID string) (message.ChannelSummary, error)
	UnarchiveChannelForUser(ctx context.Context, userID string, workspaceID string, channelID string) (message.ChannelSummary, error)
	TransferChannelOwnershipForUser(ctx context.Context, userID string, workspaceID string, channelID string, humanUserID string) error
	DismissPendingOwnerContextForUser(ctx context.Context, userID string, workspaceID string, channelID string, dismissedThroughSeq int64) error
}

// ChannelLifecycleHandler owns archive, ownership, and owner-context routes.
type ChannelLifecycleHandler struct {
	appStore      ChannelLifecycleAppStore
	realtime      ChannelRealtime
	unreadRuntime ChannelUnreadReader
}

// Archive handles POST /api/channels/:channelId/archive.
// Archives the specified channel for the authenticated user.
func (h *ChannelLifecycleHandler) Archive(r api.WorkspaceScopedRequest) (api.Response, error) {
	authenticated := r.User
	workspaceID := r.WorkspaceID()

	channelID := strings.TrimSpace(r.Gin.Param("channelId"))
	if channelID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "channelId is required")
	}

	channel, err := h.appStore.ArchiveChannelForUser(r.Context(), authenticated.User.ID, workspaceID, channelID)

	if err != nil {
		return api.Response{}, err
	}
	applyChannelMemberScopeInvalidated(h.realtime, h.unreadRuntime, workspaceID, authenticated.User.ID, r.Workspace.MemberID, channelID, unread.ScopeTypeChannel, "channel_archive")
	if h.realtime != nil {
		h.realtime.EmitChannelUpdatedForUser(workspaceID, authenticated.User.ID)
	}
	return api.OK(channelResponseFromSummary(channel)), nil
}

// Unarchive handles POST /api/channels/:channelId/unarchive.
// Unarchives the specified channel for the authenticated user.
func (h *ChannelLifecycleHandler) Unarchive(r api.WorkspaceScopedRequest) (api.Response, error) {
	authenticated := r.User
	workspaceID := r.WorkspaceID()

	channelID := strings.TrimSpace(r.Gin.Param("channelId"))
	if channelID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "channelId is required")
	}

	channel, err := h.appStore.UnarchiveChannelForUser(r.Context(), authenticated.User.ID, workspaceID, channelID)

	if err != nil {
		return api.Response{}, err
	}
	applyChannelMemberScopeInvalidated(h.realtime, h.unreadRuntime, workspaceID, authenticated.User.ID, r.Workspace.MemberID, channelID, unread.ScopeTypeChannel, "channel_unarchive")
	if h.realtime != nil {
		h.realtime.EmitChannelUpdatedForUser(workspaceID, authenticated.User.ID)
	}
	return api.OK(channelResponseFromSummary(channel)), nil
}

// TransferOwner handles POST /api/channels/:channelId/owner.
// Transfers channel ownership to another user.
func (h *ChannelLifecycleHandler) TransferOwner(r api.WorkspaceScopedJSON[dto.ChannelTransferOwnerRequest]) (api.Response, error) {
	request := r.Body
	authenticated := r.User
	workspaceID := r.WorkspaceID()

	channelID := strings.TrimSpace(r.Gin.Param("channelId"))
	if channelID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "channelId is required")
	}

	if strings.TrimSpace(request.UserID) == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "userId is required")
	}

	if err := h.appStore.TransferChannelOwnershipForUser(r.Context(), authenticated.User.ID, workspaceID, channelID, request.UserID); err != nil {
		return api.Response{}, err

	}
	if h.realtime != nil {
		h.realtime.EmitChannelUpdated(workspaceID)
	}
	return api.OK(dto.EmptyResponse{}), nil
}

// DismissOwnerContext handles POST /api/channels/:channelId/owner-context-dismiss.
// Dismisses a pending owner context notification through the given thread-local
// message sequence number.
func (h *ChannelLifecycleHandler) DismissOwnerContext(r api.WorkspaceScopedJSON[dto.ChannelDismissOwnerContextRequest]) (api.Response, error) {
	request := r.Body
	authenticated := r.User
	workspaceID := r.WorkspaceID()

	channelID := strings.TrimSpace(r.Gin.Param("channelId"))
	if channelID == "" {
		return api.Response{}, api.NewHTTPError(http.StatusBadRequest, "channelId is required")
	}

	if err := h.appStore.DismissPendingOwnerContextForUser(r.Context(), authenticated.User.ID, workspaceID, channelID, request.DismissedThroughGlobalSeq); err != nil {
		return api.Response{}, err
	}

	return api.OK(dto.EmptyResponse{}), nil

}
