package rpc

import (
	"context"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"log/slog"
	"sort"
	"time"

	claudecode "github.com/humanlayer/humanlayer/claudecode-go"
	"github.com/humanlayer/humanlayer/hld/approval"
	"github.com/humanlayer/humanlayer/hld/bus"
	"github.com/humanlayer/humanlayer/hld/session"
	"github.com/humanlayer/humanlayer/hld/store"
)

// SessionHandlers provides RPC handlers for session management
type SessionHandlers struct {
	manager         session.SessionManager
	store           store.ConversationStore
	eventBus        bus.EventBus
	approvalManager approval.Manager
}

// NewSessionHandlers creates new session RPC handlers
func NewSessionHandlers(manager session.SessionManager, store store.ConversationStore, approvalManager approval.Manager) *SessionHandlers {
	return &SessionHandlers{
		manager:         manager,
		store:           store,
		approvalManager: approvalManager,
	}
}

// SetEventBus sets the event bus for the handlers
func (h *SessionHandlers) SetEventBus(eventBus bus.EventBus) {
	h.eventBus = eventBus
}

// LaunchSessionRequest is the request for launching a new session
type LaunchSessionRequest struct {
	Query                             string                `json:"query"`
	Title                             string                `json:"title,omitempty"`
	Model                             string                `json:"model,omitempty"`
	MCPConfig                         *claudecode.MCPConfig `json:"mcp_config,omitempty"`
	PermissionPromptTool              string                `json:"permission_prompt_tool,omitempty"`
	WorkingDir                        string                `json:"working_dir,omitempty"`
	MaxTurns                          int                   `json:"max_turns,omitempty"`
	SystemPrompt                      string                `json:"system_prompt,omitempty"`
	AppendSystemPrompt                string                `json:"append_system_prompt,omitempty"`
	AllowedTools                      []string              `json:"allowed_tools,omitempty"`
	DisallowedTools                   []string              `json:"disallowed_tools,omitempty"`
	AdditionalDirectories             []string              `json:"additional_directories,omitempty"`
	CustomInstructions                string                `json:"custom_instructions,omitempty"`
	Verbose                           bool                  `json:"verbose,omitempty"`
	DangerouslySkipPermissions        bool                  `json:"dangerously_skip_permissions,omitempty"`
	DangerouslySkipPermissionsTimeout *int64                `json:"dangerously_skip_permissions_timeout,omitempty"`
}

// LaunchSessionResponse is the response for launching a new session
type LaunchSessionResponse struct {
	SessionID string `json:"session_id"`
	RunID     string `json:"run_id"`
}

// HandleLaunchSession handles the LaunchSession RPC method
func (h *SessionHandlers) HandleLaunchSession(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req LaunchSessionRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.Query == "" {
		return nil, fmt.Errorf("query is required")
	}

	// Build session config with daemon-level settings
	config := session.LaunchSessionConfig{
		SessionConfig: claudecode.SessionConfig{
			Query:                 req.Query,
			MCPConfig:             req.MCPConfig,
			PermissionPromptTool:  req.PermissionPromptTool,
			WorkingDir:            req.WorkingDir,
			MaxTurns:              req.MaxTurns,
			SystemPrompt:          req.SystemPrompt,
			AppendSystemPrompt:    req.AppendSystemPrompt,
			AllowedTools:          req.AllowedTools,
			DisallowedTools:       req.DisallowedTools,
			AdditionalDirectories: req.AdditionalDirectories,
			CustomInstructions:    req.CustomInstructions,
			Verbose:               req.Verbose,
			OutputFormat:          claudecode.OutputStreamJSON, // Always use streaming JSON for monitoring
		},
		// Daemon-level settings (not passed to Claude Code)
		Title:                             req.Title,
		DangerouslySkipPermissions:        req.DangerouslySkipPermissions,
		DangerouslySkipPermissionsTimeout: req.DangerouslySkipPermissionsTimeout,
	}

	// Parse model if provided
	if req.Model != "" {
		switch req.Model {
		case "opus":
			config.Model = claudecode.ModelOpus
		case "sonnet":
			config.Model = claudecode.ModelSonnet
		case "haiku":
			config.Model = claudecode.ModelHaiku
		default:
			// Let Claude decide the default
		}
	}

	// Launch session (RPC always launches, never creates drafts)
	session, err := h.manager.LaunchSession(ctx, config, false)
	if err != nil {
		return nil, err
	}

	return &LaunchSessionResponse{
		SessionID: session.ID,
		RunID:     session.RunID,
	}, nil
}

// ListSessionsRequest is the request for listing sessions
type ListSessionsRequest struct {
	// Could add filters here in the future
}

// ListSessionsResponse is the response for listing sessions
type ListSessionsResponse struct {
	Sessions []session.Info `json:"sessions"`
}

// HandleListSessions handles the ListSessions RPC method
func (h *SessionHandlers) HandleListSessions(ctx context.Context, params json.RawMessage) (interface{}, error) {
	// Parse request (even though it's empty for now)
	var req ListSessionsRequest
	if params != nil {
		if err := json.Unmarshal(params, &req); err != nil {
			return nil, fmt.Errorf("invalid request: %w", err)
		}
	}

	// Get all sessions
	sessions := h.manager.ListSessions()

	return &ListSessionsResponse{
		Sessions: sessions,
	}, nil
}

// GetSessionLeavesRequest is the request for getting session leaves
// TODO(3): This is gross, we should lean an alternate approach to handling filters.
type GetSessionLeavesRequest struct {
	Filter string `json:"filter,omitempty"` // "normal", "archived", or "draft"
}

// GetSessionLeavesResponse is the response for getting session leaves
type GetSessionLeavesResponse struct {
	Sessions []session.Info `json:"sessions"`
}

// HandleGetSessionLeaves handles the GetSessionLeaves RPC method
func (h *SessionHandlers) HandleGetSessionLeaves(ctx context.Context, params json.RawMessage) (interface{}, error) {
	// Parse request
	var req GetSessionLeavesRequest
	if params != nil {
		if err := json.Unmarshal(params, &req); err != nil {
			return nil, fmt.Errorf("invalid request: %w", err)
		}
	}

	// Get all sessions from manager
	sessionInfos := h.manager.ListSessions()

	// Convert to match the expected type for processing
	sessions := sessionInfos

	// Build parent-to-children map
	childrenMap := make(map[string][]string)
	for _, s := range sessions {
		if s.ParentSessionID != "" {
			childrenMap[s.ParentSessionID] = append(childrenMap[s.ParentSessionID], s.ID)
		}
	}

	// Identify leaf sessions (sessions with no children) and apply filter
	leaves := make([]session.Info, 0) // Initialize to empty slice, not nil
	for _, s := range sessions {
		children := childrenMap[s.ID]

		// Include only if session has no children (is a leaf node)
		if len(children) > 0 {
			continue
		}

		// Apply filter logic
		if !shouldIncludeSessionRPC(s, req.Filter) {
			continue
		}

		// Already have session.Info, just append
		leaves = append(leaves, s)
	}

	// Sort by last activity (newest first)
	sort.Slice(leaves, func(i, j int) bool {
		return leaves[i].LastActivityAt.After(leaves[j].LastActivityAt)
	})

	return &GetSessionLeavesResponse{
		Sessions: leaves,
	}, nil
}

// shouldIncludeSessionRPC helper function for RPC filter logic
func shouldIncludeSessionRPC(s session.Info, filterType string) bool {
	switch filterType {
	case "normal":
		return !s.Archived && s.Status != session.StatusDraft
	case "archived":
		return s.Archived
	case "draft":
		return s.Status == session.StatusDraft && !s.Archived
	case "":
		// No filter specified - include ALL sessions
		return true
	default:
		// Unknown filter - include all (graceful degradation)
		return true
	}
}

// HandleGetConversation handles the GetConversation RPC method
func (h *SessionHandlers) HandleGetConversation(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req GetConversationRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate that either SessionID or ClaudeSessionID is provided
	if req.SessionID == "" && req.ClaudeSessionID == "" {
		return nil, fmt.Errorf("either session_id or claude_session_id is required")
	}

	var events []*store.ConversationEvent
	var err error

	if req.ClaudeSessionID != "" {
		// Get conversation by Claude session ID
		events, err = h.store.GetConversation(ctx, req.ClaudeSessionID)
	} else {
		// Get conversation by session ID - always returns full history including parents
		events, err = h.store.GetSessionConversation(ctx, req.SessionID)
	}

	if err != nil {
		return nil, fmt.Errorf("failed to get conversation: %w", err)
	}

	// Convert store events to RPC events
	rpcEvents := make([]ConversationEvent, len(events))
	for i, event := range events {
		rpcEvents[i] = ConversationEvent{
			ID:                event.ID,
			SessionID:         event.SessionID,
			ClaudeSessionID:   event.ClaudeSessionID,
			Sequence:          event.Sequence,
			EventType:         event.EventType,
			CreatedAt:         event.CreatedAt.Format(time.RFC3339),
			Role:              event.Role,
			Content:           event.Content,
			ToolID:            event.ToolID,
			ToolName:          event.ToolName,
			ToolInputJSON:     event.ToolInputJSON,
			ParentToolUseID:   event.ParentToolUseID,
			ToolResultForID:   event.ToolResultForID,
			ToolResultContent: event.ToolResultContent,
			IsCompleted:       event.IsCompleted,
			ApprovalStatus:    event.ApprovalStatus,
			ApprovalID:        event.ApprovalID,
		}
	}

	return &GetConversationResponse{
		Events: rpcEvents,
	}, nil
}

// HandleGetSessionSnapshots retrieves all file snapshots for a session
func (h *SessionHandlers) HandleGetSessionSnapshots(ctx context.Context, params json.RawMessage) (interface{}, error) {
	slog.Info("HandleGetSessionSnapshots called", "params", string(params))

	// Parse request
	var req GetSessionSnapshotsRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	slog.Info("parsed request", "session_id", req.SessionID)

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}

	// Verify session exists
	_, err := h.store.GetSession(ctx, req.SessionID)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, fmt.Errorf("session not found")
		}
		return nil, fmt.Errorf("failed to get session: %w", err)
	}

	// Get snapshots from store
	snapshots, err := h.store.GetFileSnapshots(ctx, req.SessionID)
	if err != nil {
		return nil, fmt.Errorf("failed to get snapshots: %w", err)
	}

	// TODO(3): Sort snapshots explicitly (e.g., by CreatedAt) rather than relying on store's return order
	// Convert to response format
	response := &GetSessionSnapshotsResponse{
		Snapshots: make([]FileSnapshotInfo, 0, len(snapshots)),
	}

	for _, snapshot := range snapshots {
		response.Snapshots = append(response.Snapshots, FileSnapshotInfo{
			ToolID:    snapshot.ToolID,
			FilePath:  snapshot.FilePath,
			Content:   snapshot.Content,
			CreatedAt: snapshot.CreatedAt.Format(time.RFC3339),
		})
	}

	slog.Info("returning snapshots", "count", len(response.Snapshots))
	return response, nil
}

// HandleGetSessionState handles the GetSessionState RPC method
func (h *SessionHandlers) HandleGetSessionState(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req GetSessionStateRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}

	// Get session from store
	session, err := h.store.GetSession(ctx, req.SessionID)
	if err != nil {
		return nil, fmt.Errorf("failed to get session: %w", err)
	}

	// Convert to RPC session state
	state := SessionState{
		ID:                         session.ID,
		RunID:                      session.RunID,
		ClaudeSessionID:            session.ClaudeSessionID,
		ParentSessionID:            session.ParentSessionID,
		Status:                     session.Status,
		Query:                      session.Query,
		Summary:                    session.Summary,
		Title:                      session.Title,
		Model:                      session.Model,
		WorkingDir:                 session.WorkingDir,
		CreatedAt:                  session.CreatedAt.Format(time.RFC3339),
		LastActivityAt:             session.LastActivityAt.Format(time.RFC3339),
		ErrorMessage:               session.ErrorMessage,
		AutoAcceptEdits:            session.AutoAcceptEdits,
		DangerouslySkipPermissions: session.DangerouslySkipPermissions,
		Archived:                   session.Archived,
	}

	// Set optional fields
	if session.DangerouslySkipPermissionsExpiresAt != nil {
		state.DangerouslySkipPermissionsExpiresAt = session.DangerouslySkipPermissionsExpiresAt.Format(time.RFC3339)
	}
	if session.CompletedAt != nil {
		state.CompletedAt = session.CompletedAt.Format(time.RFC3339)
	}
	if session.CostUSD != nil {
		state.CostUSD = *session.CostUSD
	}
	if session.InputTokens != nil {
		state.InputTokens = *session.InputTokens
	}
	if session.OutputTokens != nil {
		state.OutputTokens = *session.OutputTokens
	}
	if session.CacheCreationInputTokens != nil {
		state.CacheCreationInputTokens = *session.CacheCreationInputTokens
	}
	if session.CacheReadInputTokens != nil {
		state.CacheReadInputTokens = *session.CacheReadInputTokens
	}
	if session.EffectiveContextTokens != nil {
		state.EffectiveContextTokens = *session.EffectiveContextTokens
	}
	// Always set context limit based on model
	state.ContextLimit = GetModelContextLimit(session.Model)
	if session.DurationMS != nil {
		state.DurationMS = *session.DurationMS
	}

	return &GetSessionStateResponse{
		Session: state,
	}, nil
}

// HandleContinueSession handles the ContinueSession RPC method
func (h *SessionHandlers) HandleContinueSession(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req ContinueSessionRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}
	if req.Query == "" {
		return nil, fmt.Errorf("query is required")
	}

	// Build session config for manager
	config := session.ContinueSessionConfig{
		ParentSessionID:       req.SessionID,
		Query:                 req.Query,
		SystemPrompt:          req.SystemPrompt,
		AppendSystemPrompt:    req.AppendSystemPrompt,
		PermissionPromptTool:  req.PermissionPromptTool,
		AllowedTools:          req.AllowedTools,
		DisallowedTools:       req.DisallowedTools,
		AdditionalDirectories: req.AdditionalDirectories,
		CustomInstructions:    req.CustomInstructions,
		MaxTurns:              req.MaxTurns,
		ProxyEnabled:          req.ProxyEnabled,
		ProxyBaseURL:          req.ProxyBaseURL,
		ProxyModelOverride:    req.ProxyModelOverride,
		ProxyAPIKey:           req.ProxyAPIKey,
	}

	// Parse MCP config if provided as JSON string
	if req.MCPConfig != "" {
		var mcpConfig claudecode.MCPConfig
		if err := json.Unmarshal([]byte(req.MCPConfig), &mcpConfig); err != nil {
			return nil, fmt.Errorf("invalid mcp_config JSON: %w", err)
		}
		config.MCPConfig = &mcpConfig
	}

	// Continue session
	session, err := h.manager.ContinueSession(ctx, config)
	if err != nil {
		return nil, err
	}

	return &ContinueSessionResponse{
		SessionID:       session.ID,
		RunID:           session.RunID,
		ClaudeSessionID: "", // Will be populated when events stream in
		ParentSessionID: req.SessionID,
	}, nil
}

// HandleInterruptSession handles the InterruptSession RPC method
func (h *SessionHandlers) HandleInterruptSession(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req InterruptSessionRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}

	// Get session from store
	session, err := h.store.GetSession(ctx, req.SessionID)
	if err != nil {
		return nil, fmt.Errorf("failed to get session: %w", err)
	}

	// Validate session is running
	if session.Status != store.SessionStatusRunning {
		return nil, fmt.Errorf("cannot interrupt session with status %s (must be running)", session.Status)
	}

	// Interrupt session
	if err := h.manager.InterruptSession(ctx, req.SessionID); err != nil {
		return nil, fmt.Errorf("failed to interrupt session: %w", err)
	}

	return &InterruptSessionResponse{
		Success:   true,
		SessionID: req.SessionID,
		Status:    "interrupting",
	}, nil
}

// HandleUpdateSessionSettings handles the UpdateSessionSettings RPC method
func (h *SessionHandlers) HandleUpdateSessionSettings(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req UpdateSessionSettingsRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}

	// Get current session to verify it exists
	session, err := h.store.GetSession(ctx, req.SessionID)
	if err != nil {
		return nil, fmt.Errorf("failed to get session: %w", err)
	}
	if session == nil {
		return nil, fmt.Errorf("session not found")
	}

	// Update session settings
	update := store.SessionUpdate{
		AutoAcceptEdits:            req.AutoAcceptEdits,
		DangerouslySkipPermissions: req.DangerouslySkipPermissions,
	}

	// Handle timeout if dangerously skip permissions is being enabled
	if req.DangerouslySkipPermissions != nil && *req.DangerouslySkipPermissions {
		// Only set expiry if timeout is provided
		if req.DangerouslySkipPermissionsTimeoutMs != nil && *req.DangerouslySkipPermissionsTimeoutMs > 0 {
			expiresAt := time.Now().Add(time.Duration(*req.DangerouslySkipPermissionsTimeoutMs) * time.Millisecond)
			expiresAtPtr := &expiresAt
			update.DangerouslySkipPermissionsExpiresAt = &expiresAtPtr
		}
	} else if req.DangerouslySkipPermissions != nil && !*req.DangerouslySkipPermissions {
		// Disabling dangerously skip permissions - clear expiry
		var nilTime *time.Time
		update.DangerouslySkipPermissionsExpiresAt = &nilTime
	}

	if err := h.store.UpdateSession(ctx, req.SessionID, update); err != nil {
		return nil, fmt.Errorf("failed to update session: %w", err)
	}

	// Auto-approve pending approvals if bypass permissions was just enabled
	if req.DangerouslySkipPermissions != nil && *req.DangerouslySkipPermissions && h.approvalManager != nil {
		// Get all pending approvals for this session
		pendingApprovals, err := h.approvalManager.GetPendingApprovals(ctx, req.SessionID)
		if err != nil {
			// Log error but don't fail the request
			slog.Error("Failed to get pending approvals for auto-approval",
				"error", err,
				"session_id", req.SessionID,
				"method", "updateSessionSettings")
		} else {
			// Auto-approve each pending approval
			for _, approval := range pendingApprovals {
				err := h.approvalManager.ApproveToolCall(ctx, approval.ID, "Auto-approved due to bypass permissions")
				if err != nil {
					// Log error but continue with other approvals
					slog.Error("Failed to auto-approve pending approval",
						"error", err,
						"approval_id", approval.ID,
						"session_id", req.SessionID,
						"method", "updateSessionSettings")
				} else {
					slog.Info("Auto-approved pending approval due to bypass permissions",
						"approval_id", approval.ID,
						"session_id", req.SessionID,
						"method", "updateSessionSettings")
				}
			}
		}
	}

	// Update event publishing
	if h.eventBus != nil {
		eventData := map[string]interface{}{
			"session_id": req.SessionID,
			"event_type": "settings_updated",
		}

		if req.AutoAcceptEdits != nil {
			eventData["auto_accept_edits"] = *req.AutoAcceptEdits
		}
		if req.DangerouslySkipPermissions != nil {
			eventData["dangerously_skip_permissions"] = *req.DangerouslySkipPermissions
			if *req.DangerouslySkipPermissions && req.DangerouslySkipPermissionsTimeoutMs != nil {
				eventData["dangerously_skip_permissions_timeout_ms"] = *req.DangerouslySkipPermissionsTimeoutMs
			}
		}

		h.eventBus.Publish(bus.Event{
			Type: bus.EventSessionSettingsChanged,
			Data: eventData,
		})
	}

	return UpdateSessionSettingsResponse{Success: true}, nil
}

// HandleGetRecentPaths handles the GetRecentPaths RPC method
func (h *SessionHandlers) HandleGetRecentPaths(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req GetRecentPathsRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	limit := req.Limit
	if limit <= 0 {
		limit = 20
	}

	paths, err := h.store.GetRecentWorkingDirs(ctx, limit)
	if err != nil {
		return nil, fmt.Errorf("get recent paths: %w", err)
	}

	// Convert store.RecentPath to RPC RecentPath with ISO 8601 timestamps
	rpcPaths := make([]RecentPath, len(paths))
	for i, p := range paths {
		rpcPaths[i] = RecentPath{
			Path:       p.Path,
			LastUsed:   p.LastUsed.Format(time.RFC3339),
			UsageCount: p.UsageCount,
		}
	}

	return &GetRecentPathsResponse{Paths: rpcPaths}, nil
}

// HandleUpdateSessionTitle handles the UpdateSessionTitle RPC method
func (h *SessionHandlers) HandleUpdateSessionTitle(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req UpdateSessionTitleRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}

	// Update session title
	update := store.SessionUpdate{
		Title: &req.Title,
	}

	if err := h.store.UpdateSession(ctx, req.SessionID, update); err != nil {
		return nil, fmt.Errorf("failed to update session: %w", err)
	}

	// Publish event for UI updates
	if h.eventBus != nil {
		h.eventBus.Publish(bus.Event{
			Type: bus.EventSessionStatusChanged,
			Data: map[string]interface{}{
				"session_id": req.SessionID,
				"title":      req.Title,
			},
		})
	}

	return &UpdateSessionTitleResponse{
		Success: true,
	}, nil
}

// ArchiveSessionRequest is the request for archiving/unarchiving a session
type ArchiveSessionRequest struct {
	SessionID string `json:"session_id"` // The session to archive/unarchive
	Archived  bool   `json:"archived"`   // Whether to archive (true) or unarchive (false)
}

// ArchiveSessionResponse is the response for archiving/unarchiving a session
type ArchiveSessionResponse struct {
	Success bool `json:"success"`
}

// HandleArchiveSession handles the ArchiveSession RPC method
func (h *SessionHandlers) HandleArchiveSession(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req ArchiveSessionRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if req.SessionID == "" {
		return nil, fmt.Errorf("session_id is required")
	}

	// Update session in store
	err := h.store.UpdateSession(ctx, req.SessionID, store.SessionUpdate{
		Archived: &req.Archived,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to archive session: %w", err)
	}

	// TODO: Notify subscribers via event bus

	return &ArchiveSessionResponse{Success: true}, nil
}

// BulkArchiveSessionsRequest is the request for bulk archiving/unarchiving sessions
type BulkArchiveSessionsRequest struct {
	SessionIDs []string `json:"session_ids"` // The sessions to archive/unarchive
	Archived   bool     `json:"archived"`    // Whether to archive (true) or unarchive (false)
}

// BulkArchiveSessionsResponse is the response for bulk archiving/unarchiving sessions
type BulkArchiveSessionsResponse struct {
	Success        bool     `json:"success"`
	FailedSessions []string `json:"failed_sessions,omitempty"` // Sessions that failed to archive
}

// HandleBulkArchiveSessions handles the BulkArchiveSessions RPC method
func (h *SessionHandlers) HandleBulkArchiveSessions(ctx context.Context, params json.RawMessage) (interface{}, error) {
	var req BulkArchiveSessionsRequest
	if err := json.Unmarshal(params, &req); err != nil {
		return nil, fmt.Errorf("invalid request: %w", err)
	}

	// Validate required fields
	if len(req.SessionIDs) == 0 {
		return nil, fmt.Errorf("session_ids is required and cannot be empty")
	}

	var failedSessions []string

	// Update each session
	for _, sessionID := range req.SessionIDs {
		err := h.store.UpdateSession(ctx, sessionID, store.SessionUpdate{
			Archived: &req.Archived,
		})
		if err != nil {
			// Log the error but continue processing other sessions
			failedSessions = append(failedSessions, sessionID)
		}
	}

	// TODO: Notify subscribers via event bus for successful updates

	return &BulkArchiveSessionsResponse{
		Success:        len(failedSessions) == 0,
		FailedSessions: failedSessions,
	}, nil
}

// Register registers all session handlers with the RPC server
func (h *SessionHandlers) Register(server *Server) {
	server.Register("launchSession", h.HandleLaunchSession)
	server.Register("listSessions", h.HandleListSessions)
	server.Register("getSessionLeaves", h.HandleGetSessionLeaves)
	server.Register("getConversation", h.HandleGetConversation)
	server.Register("getSessionState", h.HandleGetSessionState)
	server.Register("continueSession", h.HandleContinueSession)
	server.Register("interruptSession", h.HandleInterruptSession)
	server.Register("getSessionSnapshots", h.HandleGetSessionSnapshots)
	server.Register("updateSessionSettings", h.HandleUpdateSessionSettings)
	server.Register("updateSessionTitle", h.HandleUpdateSessionTitle)
	server.Register("getRecentPaths", h.HandleGetRecentPaths)
	server.Register("archiveSession", h.HandleArchiveSession)
	server.Register("bulkArchiveSessions", h.HandleBulkArchiveSessions)
}
