import { createStore } from '@xstate/store';
import { mergeMessages } from './inboxes/merge-messages.js';
import { idToAutomergeId } from './utils/automergeId.js';
const initialStoreContext = {
  spaces: [],
  spacesLoadingIsPending: true,
  updatesInFlight: [],
  invitations: [],
  repo: null,
  identities: {},
  authenticated: false,
  identity: null,
  privyIdentity: null,
  lastUpdateClock: {},
  accountInboxes: []
};
export const store = /*#__PURE__*/createStore({
  context: initialStoreContext,
  on: {
    setInvitations: (context, event) => {
      return {
        ...context,
        invitations: event.invitations
      };
    },
    reset: context => {
      // once the repo is initialized, there is no need to reset it
      return {
        ...initialStoreContext,
        repo: context.repo
      };
    },
    addUpdateInFlight: (context, event) => {
      return {
        ...context,
        updatesInFlight: [...context.updatesInFlight, event.updateId]
      };
    },
    removeUpdateInFlight: (context, event) => {
      return {
        ...context,
        updatesInFlight: context.updatesInFlight.filter(id => id !== event.updateId)
      };
    },
    setSpacesList: (context, event) => {
      if (!context.repo) {
        return context;
      }
      let storeContext = {
        ...context,
        spacesLoadingIsPending: false
      };
      for (const space of event.spaces) {
        const existingSpace = context.spaces.find(s => s.id === space.id);
        const lastUpdateClock = context.lastUpdateClock[space.id] ?? -1;
        const result = context.repo.findWithProgress(idToAutomergeId(space.id));
        // set it to ready to interact with the document
        result.handle.doneLoading();
        if (existingSpace) {
          storeContext = {
            ...storeContext,
            spaces: storeContext.spaces.map(existingSpace => {
              if (existingSpace.id === space.id) {
                const newSpace = {
                  id: existingSpace.id,
                  name: existingSpace.name,
                  events: existingSpace.events ?? [],
                  state: existingSpace.state,
                  keys: existingSpace.keys ?? [],
                  automergeDocHandle: result.handle,
                  inboxes: existingSpace.inboxes ?? []
                };
                return newSpace;
              }
              return existingSpace;
            }),
            lastUpdateClock: {
              ...storeContext.lastUpdateClock,
              [space.id]: lastUpdateClock
            }
          };
        } else {
          storeContext = {
            ...storeContext,
            spaces: [...storeContext.spaces, {
              id: space.id,
              name: space.name,
              events: [],
              state: undefined,
              keys: [],
              inboxes: [],
              automergeDocHandle: result.handle
            }],
            lastUpdateClock: {
              ...storeContext.lastUpdateClock,
              [space.id]: -1
            }
          };
        }
      }
      return storeContext;
    },
    applyEvent: (context, event) => {
      return {
        ...context,
        spaces: context.spaces.map(space => {
          if (space.id === event.spaceId) {
            return {
              ...space,
              events: [...space.events, event.event],
              state: event.state
            };
          }
          return space;
        })
      };
    },
    updateConfirmed: (context, event) => {
      return {
        ...context,
        lastUpdateClock: {
          ...context.lastUpdateClock,
          [event.spaceId]: event.clock
        }
      };
    },
    applyUpdate: (context, event) => {
      const lastUpdateClock = context.lastUpdateClock[event.spaceId] ?? -1;
      if (event.firstUpdateClock === lastUpdateClock + 1) {
        return {
          ...context,
          lastUpdateClock: {
            ...context.lastUpdateClock,
            [event.spaceId]: event.lastUpdateClock
          }
        };
      }
      // TODO else case: request missing updates from server
      return context;
    },
    addVerifiedIdentity: (context, event) => {
      const existingIdentity = context.identities[event.accountAddress]?.find(identity => identity.signaturePublicKey === event.signaturePublicKey);
      if (existingIdentity) {
        return context;
      }
      if (context.identities[event.accountAddress]) {
        return {
          ...context,
          identities: {
            ...context.identities,
            [event.accountAddress]: [...context.identities[event.accountAddress], {
              encryptionPublicKey: event.encryptionPublicKey,
              signaturePublicKey: event.signaturePublicKey,
              accountProof: event.accountProof,
              keyProof: event.keyProof,
              appId: event.appId
            }]
          }
        };
      }
      return {
        ...context,
        identities: {
          ...context.identities,
          [event.accountAddress]: [{
            encryptionPublicKey: event.encryptionPublicKey,
            signaturePublicKey: event.signaturePublicKey,
            accountProof: event.accountProof,
            keyProof: event.keyProof,
            appId: event.appId
          }]
        }
      };
    },
    setSpaceInbox: (context, event) => {
      return {
        ...context,
        spaces: context.spaces.map(space => {
          if (space.id === event.spaceId) {
            const existingInbox = space.inboxes.find(inbox => inbox.inboxId === event.inbox.inboxId);
            if (existingInbox) {
              return {
                ...space,
                inboxes: space.inboxes.map(inbox => {
                  if (inbox.inboxId === event.inbox.inboxId) {
                    const {
                      messages,
                      seenMessageIds
                    } = mergeMessages(existingInbox.messages, existingInbox.seenMessageIds, event.inbox.messages);
                    return {
                      ...event.inbox,
                      messages,
                      seenMessageIds
                    };
                  }
                  return inbox;
                })
              };
            }
            return {
              ...space,
              inboxes: [...space.inboxes, event.inbox]
            };
          }
          return space;
        })
      };
    },
    setSpaceInboxMessages: (context, event) => {
      return {
        ...context,
        spaces: context.spaces.map(space => {
          if (space.id === event.spaceId) {
            return {
              ...space,
              inboxes: space.inboxes.map(inbox => {
                if (inbox.inboxId === event.inboxId) {
                  const {
                    messages,
                    seenMessageIds
                  } = mergeMessages(inbox.messages, inbox.seenMessageIds, event.messages);
                  return {
                    ...inbox,
                    messages,
                    seenMessageIds,
                    lastMessageClock: new Date(Math.max(new Date(inbox.lastMessageClock).getTime(), new Date(event.lastMessageClock).getTime())).toISOString()
                  };
                }
                return inbox;
              })
            };
          }
          return space;
        })
      };
    },
    setAccountInbox: (context, event) => {
      const existingInbox = context.accountInboxes.find(inbox => inbox.inboxId === event.inbox.inboxId);
      if (existingInbox) {
        return {
          ...context,
          accountInboxes: context.accountInboxes.map(inbox => {
            if (inbox.inboxId === event.inbox.inboxId) {
              const {
                messages,
                seenMessageIds
              } = mergeMessages(existingInbox.messages, existingInbox.seenMessageIds, event.inbox.messages);
              return {
                ...event.inbox,
                messages,
                seenMessageIds
              };
            }
            return inbox;
          })
        };
      }
      return {
        ...context,
        accountInboxes: [...context.accountInboxes, event.inbox]
      };
    },
    setAccountInboxMessages: (context, event) => {
      return {
        ...context,
        accountInboxes: context.accountInboxes.map(inbox => {
          if (inbox.inboxId === event.inboxId) {
            const {
              messages,
              seenMessageIds
            } = mergeMessages(inbox.messages, inbox.seenMessageIds, event.messages);
            return {
              ...inbox,
              messages,
              seenMessageIds,
              lastMessageClock: new Date(Math.max(new Date(inbox.lastMessageClock).getTime(), new Date(event.lastMessageClock).getTime())).toISOString()
            };
          }
          return inbox;
        })
      };
    },
    setSpace: (context, event) => {
      const existingSpace = context.spaces.find(s => s.id === event.spaceId);
      if (!existingSpace && context.repo) {
        const result = context.repo.findWithProgress(idToAutomergeId(event.spaceId));
        // set it to ready to interact with the document
        result.handle.doneLoading();
        const newSpace = {
          name: event.name,
          id: event.spaceId,
          events: event.events,
          state: event.spaceState,
          keys: event.keys,
          automergeDocHandle: result.handle,
          inboxes: event.inboxes ?? []
        };
        return {
          ...context,
          spaces: [...context.spaces, newSpace],
          lastUpdateClock: {
            ...context.lastUpdateClock,
            [event.spaceId]: -1
          }
        };
      }
      let lastUpdateClock = context.lastUpdateClock[event.spaceId] ?? -1;
      if (event.updates?.firstUpdateClock === lastUpdateClock + 1) {
        lastUpdateClock = event.updates.lastUpdateClock;
      } else {
        // TODO request missing updates from server
      }
      return {
        ...context,
        spaces: context.spaces.map(space => {
          if (space.id === event.spaceId) {
            // Merge inboxes: keep existing ones and add new ones
            const mergedInboxes = [...space.inboxes];
            for (const newInbox of event.inboxes ?? []) {
              const existingInboxIndex = mergedInboxes.findIndex(inbox => inbox.inboxId === newInbox.inboxId);
              if (existingInboxIndex === -1) {
                // Only add if it's a new inbox
                mergedInboxes.push(newInbox);
              }
            }
            return {
              ...space,
              events: event.events,
              state: event.spaceState,
              keys: event.keys,
              inboxes: mergedInboxes
            };
          }
          return space;
        }),
        lastUpdateClock: {
          ...context.lastUpdateClock,
          [event.spaceId]: lastUpdateClock
        }
      };
    },
    setAuth: (context, event) => {
      return {
        ...context,
        authenticated: true,
        // TODO: remove hard-coded account address and use the one from the identity
        identity: {
          ...event.identity
        },
        privyIdentity: null
      };
    },
    setPrivyAuth: (context, event) => {
      return {
        ...context,
        authenticated: true,
        privyIdentity: {
          ...event.identity
        },
        identity: null
      };
    },
    resetAuth: context => {
      return {
        ...context,
        identity: null,
        privyIdentity: null,
        authenticated: false
      };
    },
    setRepo: (context, event) => {
      return {
        ...context,
        repo: event.repo
      };
    }
  }
});
//# sourceMappingURL=store.js.map