import { requireCampaignAccess, requireStageTwoUser, stageTwoApiError, stageTwoDatabase, stageTwoUuid } from '~/server/utils/stage-two-supabase' import { visibleProfile, type ProfileRecord } from '~/server/utils/profile' export default defineEventHandler(async (event) => { try { const user = await requireStageTwoUser(event) const campaignId = stageTwoUuid(getRouterParam(event, 'id'), 'campaign id') const access = await requireCampaignAccess(campaignId, user.id) const campaign = access.campaign const worldId = String(campaign.world_id) const [worlds, members, characters, openRounds, rounds] = await Promise.all([ stageTwoDatabase>>( `worlds?select=id,title,genre,tone,premise,content_boundaries,hook,opening_scene&id=eq.${worldId}&limit=1`, ), stageTwoDatabase>>( `campaign_members?select=id,user_id,role,active,ai_takeover_allowed,joined_at&campaign_id=eq.${campaignId}&order=joined_at.asc`, ), stageTwoDatabase>>( `characters?select=id,campaign_id,user_id,name,concept,controller,abilities,hp,max_hp,defense,proficiency,inventory,statuses,persona,rules_state,created_at&campaign_id=eq.${campaignId}&order=created_at.asc`, ), stageTwoDatabase>>( `rounds?select=id,campaign_id,number,status,forced_by,narration,next_prompt,queued_at,resolved_at,error,created_at&campaign_id=eq.${campaignId}&status=eq.open&order=number.desc&limit=1`, ), stageTwoDatabase>>( `rounds?select=id,campaign_id,number,status,forced_by,narration,next_prompt,queued_at,resolved_at,error,created_at&campaign_id=eq.${campaignId}&order=number.desc&limit=30`, ), ]) const fallbackRounds = openRounds.length ? [] : await stageTwoDatabase>>( `rounds?select=id,campaign_id,number,status,forced_by,narration,next_prompt,queued_at,resolved_at,error,created_at&campaign_id=eq.${campaignId}&order=number.desc&limit=1`, ) const round = openRounds[0] ?? fallbackRounds[0] ?? null const userIds = [...new Set(members.map(member => String(member.user_id)))] const profiles = userIds.length ? await stageTwoDatabase( `profiles?select=id,display_name,description,avatar_path,created_at,updated_at&id=in.(${userIds.join(',')})`, ) : [] const supabaseUrl = useRuntimeConfig().supabaseUrl const profileById = new Map(profiles.map(profile => [profile.id, visibleProfile(profile, supabaseUrl)])) const visibleMembers = members.map(member => ({ ...member, profile: profileById.get(String(member.user_id)) ?? null })) const visibleRounds = rounds.slice().reverse() const visibleRoundIds = visibleRounds.map(item => String(item.id)) const [intents, events, diceRolls, sceneStates, questStates, relationships, memories, storySummaries, auditEntries] = await Promise.all([ round ? stageTwoDatabase>>( `player_intents?select=id,round_id,member_id,character_id,action,ready,created_at,updated_at&round_id=eq.${String(round.id)}&order=created_at.asc`, ) : Promise.resolve([]), stageTwoDatabase>>( `game_events?select=id,campaign_id,round_id,event_type,payload,created_at&campaign_id=eq.${campaignId}&order=created_at.desc&limit=50`, ), visibleRoundIds.length ? stageTwoDatabase>>( `dice_rolls?select=id,round_id,actor_id,target_id,check_kind,formula,rolls,kept,modifier,total,difficulty,success,created_at&round_id=in.(${visibleRoundIds.join(',')})&order=created_at.asc`, ) : Promise.resolve([]), stageTwoDatabase>>( `scene_states?select=campaign_id,location_id,summary,active_entity_ids,tags,through_round,updated_at&campaign_id=eq.${campaignId}&limit=1`, ), stageTwoDatabase>>( `quest_states?select=campaign_id,quest_entity_id,status,summary,tags,through_round,updated_at&campaign_id=eq.${campaignId}&order=updated_at.desc`, ), stageTwoDatabase>>( `relationships?select=source_entity_id,target_entity_id,score,notes&campaign_id=eq.${campaignId}&order=score.desc&limit=30`, ), stageTwoDatabase>>( `memories?select=id,round_id,summary,importance,tags,entity_ids,created_at&campaign_id=eq.${campaignId}&order=importance.desc,created_at.desc&limit=20`, ), stageTwoDatabase>>( `story_summaries?select=id,through_round,summary,created_at&campaign_id=eq.${campaignId}&order=through_round.desc&limit=1`, ), access.owner ? stageTwoDatabase>>( `audit_entries?select=id,actor_id,action,entity_type,entity_id,before_state,after_state,created_at&campaign_id=eq.${campaignId}&order=created_at.desc&limit=50`, ) : Promise.resolve([]), ]) return { campaign, world: worlds[0] ?? null, members: visibleMembers, characters, round, rounds: visibleRounds, intents, events: events.slice().reverse(), diceRolls, sceneState: sceneStates[0] ?? null, activeGoals: questStates.filter(quest => quest.status === 'active'), relationships, memories, storySummary: storySummaries[0] ?? null, auditEntries, } } catch (error) { stageTwoApiError(error) } })