import { Graph } from '@graphprotocol/grc-20';
import { Constants, Utils } from '@graphprotocol/hypergraph';
import * as Either from 'effect/Either';
import * as Option from 'effect/Option';
import * as Schema from 'effect/Schema';
import * as SchemaAST from 'effect/SchemaAST';
import { request } from 'graphql-request';
import { buildRelationsSelection } from '../utils/relation-query-helpers.js';
import { normalizeSpaceIds } from './internal/normalize-space-ids.js';
import { normalizeSpaceSelection } from './internal/space-selection.js';
const buildEntitiesQuery = (relationInfoLevel1, useOrderBy, spaceSelection, includeSpaceIds) => {
  const level1Relations = buildRelationsSelection(relationInfoLevel1, spaceSelection.mode);
  const spaceIdsSelection = includeSpaceIds ? '\n    spaceIds' : '';
  const queryName = useOrderBy ? 'entitiesOrderedByProperty' : 'entities';
  const variableDefinitions = [spaceSelection.mode === 'single' ? '$spaceId: UUID!' : spaceSelection.mode === 'many' ? '$spaceIds: [UUID!]!' : undefined, '$typeIds: [UUID!]!', useOrderBy ? '$propertyId: UUID!' : undefined, useOrderBy ? '$sortDirection: SortOrder!' : undefined, '$first: Int', '$filter: EntityFilter!', '$offset: Int'].filter(Boolean).join(', ');
  const orderByArgs = useOrderBy ? 'propertyId: $propertyId\n    sortDirection: $sortDirection\n    ' : '';
  const entitySpaceFilter = spaceSelection.mode === 'single' ? 'spaceIds: {in: [$spaceId]},' : spaceSelection.mode === 'many' ? 'spaceIds: {in: $spaceIds},' : '';
  const valuesListFilter = spaceSelection.mode === 'single' ? '(filter: { spaceId: { is: $spaceId } })' : spaceSelection.mode === 'many' ? '(filter: { spaceId: { in: $spaceIds } })' : '';
  return `
query ${queryName}(${variableDefinitions}) {
  entities: ${queryName}(
    ${orderByArgs}filter: { and: [{
      relations: {some: {typeId: {is: "8f151ba4-de20-4e3c-9cb4-99ddf96f48f1"}, toEntityId: {in: $typeIds}}}, 
      ${entitySpaceFilter}
    }, $filter]}
    first: $first
    offset: $offset
  ) {
    id
    name${spaceIdsSelection}
    valuesList${valuesListFilter} {
      propertyId
      string
      boolean
      number
      time
      point
    }
    ${level1Relations}
  }
}`;
};
export const parseResult = (queryData, type, relationInfoLevel1, options) => {
  const includeSpaceIds = options?.includeSpaceIds ?? false;
  const schemaWithId = Utils.addIdSchemaField(type);
  const decode = Schema.decodeUnknownEither(schemaWithId);
  const data = [];
  const invalidEntities = [];
  const invalidRelationEntities = [];
  for (const queryEntity of queryData.entities) {
    let rawEntity = {
      id: queryEntity.id
    };
    const ast = type.ast;
    for (const prop of ast.propertySignatures) {
      const propType = prop.isOptional && SchemaAST.isUnion(prop.type) ? prop.type.types.find(member => !SchemaAST.isUndefinedKeyword(member)) ?? prop.type : prop.type;
      const result = SchemaAST.getAnnotation(Constants.PropertyIdSymbol)(propType);
      if (Option.isSome(result)) {
        const value = queryEntity.valuesList.find(a => a.propertyId === result.value);
        if (value) {
          const rawValue = Utils.convertPropertyValue(value, propType);
          if (rawValue) {
            rawEntity[String(prop.name)] = rawValue;
          }
        }
      }
    }
    const {
      rawEntity: relationEntities,
      invalidRelations
    } = Utils.convertRelations(queryEntity, ast, relationInfoLevel1);
    // @ts-expect-error
    rawEntity = {
      ...rawEntity,
      ...relationEntities
    };
    if (invalidRelations.length > 0) {
      invalidRelationEntities.push(...invalidRelations);
    }
    const decodeResult = decode({
      ...rawEntity,
      __deleted: false
    });
    if (Either.isRight(decodeResult)) {
      const baseEntity = decodeResult.right;
      const entityWithSpaceIds = includeSpaceIds ? {
        ...baseEntity,
        spaceIds: normalizeSpaceIds(queryEntity.spaceIds)
      } : baseEntity;
      data.push(entityWithSpaceIds);
    } else {
      const invalidRawEntity = includeSpaceIds ? {
        ...rawEntity,
        spaceIds: normalizeSpaceIds(queryEntity.spaceIds)
      } : rawEntity;
      invalidEntities.push({
        raw: invalidRawEntity,
        error: decodeResult.left
      });
    }
  }
  return {
    data,
    invalidEntities,
    invalidRelationEntities
  };
};
export const findManyPublic = async (type, params) => {
  const {
    filter,
    include,
    space,
    spaces,
    first = 100,
    offset = 0,
    orderBy,
    includeSpaceIds: includeSpaceIdsParam,
    logInvalidResults = true
  } = params ?? {};
  const includeSpaceIds = includeSpaceIdsParam ?? false;
  // constructing the relation type ids for the query
  const relationTypeIds = Utils.getRelationTypeIds(type, include);
  const typeIds = SchemaAST.getAnnotation(Constants.TypeIdsSymbol)(type.ast).pipe(Option.getOrElse(() => []));
  let orderByPropertyId;
  let sortDirection;
  if (orderBy) {
    const ast = type.ast;
    const propertySignature = ast.propertySignatures.find(prop => String(prop.name) === String(orderBy.property));
    if (!propertySignature) {
      throw new Error(`Cannot order by unknown property "${String(orderBy.property)}"`);
    }
    const propertyType = propertySignature.isOptional && SchemaAST.isUnion(propertySignature.type) ? propertySignature.type.types.find(member => !SchemaAST.isUndefinedKeyword(member)) ?? propertySignature.type : propertySignature.type;
    const propertyIdAnnotation = SchemaAST.getAnnotation(Constants.PropertyIdSymbol)(propertyType);
    if (Option.isNone(propertyIdAnnotation)) {
      throw new Error(`Property "${String(orderBy.property)}" is missing a propertyId annotation`);
    }
    orderByPropertyId = propertyIdAnnotation.value;
    sortDirection = orderBy.direction === 'asc' ? 'ASC' : 'DESC';
  }
  // Build the query dynamically with aliases for each relation type ID
  const spaceSelection = normalizeSpaceSelection(space, spaces);
  // Build the query dynamically with aliases for each relation type ID
  const queryDocument = buildEntitiesQuery(relationTypeIds, Boolean(orderBy), spaceSelection, includeSpaceIds);
  const filterParams = filter ? Utils.translateFilterToGraphql(filter, type) : {};
  const queryVariables = {
    typeIds,
    first,
    filter: filterParams,
    offset
  };
  if (spaceSelection.mode === 'single') {
    queryVariables.spaceId = spaceSelection.spaceId;
  } else if (spaceSelection.mode === 'many') {
    queryVariables.spaceIds = spaceSelection.spaceIds;
  }
  if (orderByPropertyId && sortDirection) {
    queryVariables.propertyId = orderByPropertyId;
    queryVariables.sortDirection = sortDirection;
  }
  const result = await request(`${Graph.TESTNET_API_ORIGIN}/graphql`, queryDocument, queryVariables);
  const {
    data,
    invalidEntities,
    invalidRelationEntities
  } = parseResult(result, type, relationTypeIds, includeSpaceIdsParam === undefined ? undefined : {
    includeSpaceIds: includeSpaceIdsParam
  });
  if (logInvalidResults) {
    if (invalidEntities.length > 0) {
      console.warn('Entities where decoding failed were dropped', invalidEntities);
    }
    if (invalidRelationEntities.length > 0) {
      console.warn('Relation entities where decoding failed were dropped', invalidRelationEntities);
    }
  }
  return {
    data,
    invalidEntities,
    invalidRelationEntities
  };
};
//# sourceMappingURL=find-many-public.js.map