-- allium: 1
-- Domain Event Bus (issue #26, phase 2)
-- Scope: extension (multi-client synchronization over Phoenix.PubSub)
-- Distilled from: lib/bds/events.ex, context broadcast call sites,
--                 lib/bds/desktop/shell_live.ex, lib/bds/cli_sync/watcher.ex

entity EntityChangedEvent {
    project_id: String
    entity: String                  -- post, media, tag, template, script, project
    entity_id: String
    action: created | updated | deleted
    -- Same topic and payload shape as the CLI sync watcher, so one
    -- subscription covers in-app mutations and external CLI writes.
}

entity SettingsChangedEvent {
    project_id: String?             -- absent for a global setting
    key: String                     -- e.g. ui.language
}

surface EventBusSurface {
    facing _: EventBus

    provides:
        ContextMutationSucceeded(project_id, entity, entity_id, action)
        GlobalSettingWritten(key)
        ClientSubscribed()
        ClientUnsubscribed()
}

rule BroadcastEntityMutation {
    when: ContextMutationSucceeded(project_id, entity, entity_id, action)
    -- Posts, Media, Tags, Templates, Scripts broadcast after every
    -- successful create/update/publish/delete (publish maps to updated).
    ensures: EntityChangedEvent.created(
        project_id: project_id,
        entity: entity,
        entity_id: entity_id,
        action: action
    )
}

rule BroadcastSettingsChange {
    when: GlobalSettingWritten(key)
    ensures: SettingsChangedEvent.created(key: key)
}

rule ClientSynchronization {
    when: ClientSubscribed()
    -- Every shell subscribes on mount. Each subscriber receives events in
    -- publish order and refreshes only the affected project; deleted entities
    -- close their open tabs. Global and active-project setting changes refresh
    -- every cached setting consumer even when the Settings surface is closed;
    -- separately cached runtime controls such as airplane mode update too. A
    -- refresh never writes the mutation again.
    ensures: ClientRefreshOnEvent()
}

rule ClientUnsubscription {
    when: ClientUnsubscribed()
    -- A detached client receives no later events.
    ensures: ClientDetached()
}

rule ServerSideUiLanguage {
    when: GlobalSettingWritten(key)
    requires: key = "ui.language"
    -- The UI language is a single server-side setting: changing it in any
    -- client persists it and re-renders every connected client. The OS
    -- locale is only the fallback when the setting is unset.
    ensures: AllClientsRelocalized()
}
