import { Type, Utils } from '@graphprotocol/hypergraph';
import { useQueryLocal } from './HypergraphSpaceContext.js';
import { useQueryPublic } from './internal/use-query-public.js';
// @ts-expect-error TODO: remove this function
const _mergeEntities = (publicEntities, localEntities, localDeletedEntities) => {
  const mergedData = [];
  for (const entity of publicEntities) {
    const deletedEntity = localDeletedEntities.find(e => e.id === entity.id);
    if (deletedEntity) {
      continue;
    }
    const localEntity = localEntities.find(e => e.id === entity.id);
    if (localEntity) {
      const mergedEntity = {
        ...entity
      };
      for (const key in entity) {
        mergedEntity[key] = localEntity[key];
      }
      mergedData.push(mergedEntity);
    } else {
      mergedData.push(entity);
    }
  }
  // find all local entities that are not in the public result
  const localEntitiesNotInPublic = localEntities.filter(e => !publicEntities.some(p => p.id === e.id));
  mergedData.push(...localEntitiesNotInPublic);
  return mergedData;
};
// @ts-expect-error TODO: remove this function
const _getDiff = (type, publicEntities, localEntities, localDeletedEntities) => {
  const deletedEntities = [];
  const updatedEntities = [];
  for (const entity of publicEntities) {
    const deletedEntity = localDeletedEntities.find(e => e.id === entity.id);
    if (deletedEntity) {
      deletedEntities.push(deletedEntity);
      continue;
    }
    const localEntity = localEntities.find(e => e.id === entity.id);
    if (localEntity) {
      const diff = {};
      for (const [key, field] of Object.entries(type.fields)) {
        if (key === '__version' || key === '__deleted') {
          continue;
        }
        if (Utils.isRelationField(field)) {
          const relationIds = entity[key].map(e => e.id);
          const localRelationIds = localEntity[key].map(e => e.id);
          if (relationIds.length !== localRelationIds.length || relationIds.some(id => !localRelationIds.includes(id))) {
            const removedIds = relationIds.filter(id => !localRelationIds.includes(id));
            const addedIds = localRelationIds.filter(id => !relationIds.includes(id));
            // get a list of the ids that didn't get added or removed
            const unchangedIds = localRelationIds.filter(id => !addedIds.includes(id) && !removedIds.includes(id));
            diff[key] = {
              type: 'relation',
              current: entity[key],
              new: localEntity[key],
              addedIds,
              removedIds,
              unchangedIds
            };
          }
        } else {
          if (field === Type.Date) {
            if (entity[key].getTime() !== localEntity[key].getTime()) {
              diff[key] = {
                type: 'property',
                current: entity[key],
                new: localEntity[key]
              };
            }
          } else if (field === Type.Point) {
            if (entity[key].join(',') !== localEntity[key].join(',')) {
              diff[key] = {
                type: 'property',
                current: entity[key],
                new: localEntity[key]
              };
            }
          } else if (entity[key] !== localEntity[key]) {
            diff[key] = {
              type: 'property',
              current: entity[key],
              new: localEntity[key]
            };
          }
        }
      }
      if (Object.keys(diff).length > 0) {
        updatedEntities.push({
          id: entity.id,
          current: entity,
          new: localEntity,
          diff
        });
      }
    } else {
      // TODO update the local entity in this place?
    }
  }
  const newEntities = localEntities.filter(e => !publicEntities.some(p => p.id === e.id));
  return {
    newEntities,
    deletedEntities,
    updatedEntities
  };
};
const preparePublishDummy = () => undefined;
export function useQuery(type, params) {
  const {
    mode,
    filter,
    include,
    space,
    first
  } = params;
  const publicResult = useQueryPublic(type, {
    enabled: mode === 'public',
    include,
    first,
    space
  });
  const localResult = useQueryLocal(type, {
    enabled: mode === 'private',
    filter,
    include,
    space
  });
  // const mapping = useSelector(store, (state) => state.context.mapping);
  // const generateUpdateOps = useGenerateUpdateOps(type, mode === 'merged');
  // const mergedData = useMemo(() => {
  //   if (mode !== 'merged' || publicResult.isLoading) {
  //     return localResult.entities;
  //   }
  //   return mergeEntities(publicResult.data, localResult.entities, localResult.deletedEntities);
  // }, [mode, publicResult.isLoading, publicResult.data, localResult.entities, localResult.deletedEntities]);
  if (mode === 'public') {
    return {
      ...publicResult,
      deleted: [],
      preparePublish: preparePublishDummy
    };
  }
  return {
    ...publicResult,
    data: localResult.entities,
    deleted: localResult.deletedEntities,
    preparePublish: preparePublishDummy
  };
  // const preparePublish = async (): Promise<PublishDiffInfo> => {
  //   // @ts-expect-error TODO should use the actual type instead of the name in the mapping
  //   const typeName = type.name;
  //   const mappingEntry = mapping?.[typeName];
  //   if (!mappingEntry) {
  //     throw new Error(`Mapping entry for ${typeName} not found`);
  //   }
  //   const result = await publicResult.refetch();
  //   if (!result.data) {
  //     throw new Error('No data found');
  //   }
  //   const diff = getDiff(
  //     type,
  //     parseResult(result.data, type, mappingEntry, mapping).data,
  //     localResult.entities,
  //     localResult.deletedEntities,
  //   );
  //   const newEntities = diff.newEntities.map((entity) => {
  //     const { ops: createOps } = generateCreateOps(entity);
  //     return { id: entity.id, entity, ops: createOps };
  //   });
  //   const updatedEntities = diff.updatedEntities.map((updatedEntityInfo) => {
  //     const { ops: updateOps } = generateUpdateOps({ id: updatedEntityInfo.id, diff: updatedEntityInfo.diff });
  //     return { ...updatedEntityInfo, ops: updateOps };
  //   });
  //   const deletedEntities = await Promise.all(
  //     diff.deletedEntities.map(async (entity) => {
  //       const deleteOps = await generateDeleteOps(entity);
  //       return { id: entity.id, entity, ops: deleteOps };
  //     }),
  //   );
  //   return { newEntities, updatedEntities, deletedEntities };
  // };
  // return {
  //   ...publicResult,
  //   data: mergedData,
  //   deleted: localResult.deletedEntities,
  //   preparePublish: !publicResult.isLoading ? preparePublish : preparePublishDummy,
  // };
}
//# sourceMappingURL=use-query.js.map