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 { convertPropertyValue } from './convert-property-value.js';
import { getRelationAlias } from './relation-query-helpers.js';
export const convertRelations = (queryEntity, ast, relationInfo = []) => {
  const rawEntity = {};
  const invalidRelations = [];
  for (const prop of ast.propertySignatures) {
    const result = SchemaAST.getAnnotation(Constants.PropertyIdSymbol)(prop.type);
    if (Utils.isRelation(prop.type) && Option.isSome(result)) {
      rawEntity[String(prop.name)] = [];
      if (!SchemaAST.isTupleType(prop.type)) {
        continue;
      }
      const relationType = prop.type;
      const relationTransformation = relationType.rest[0]?.type;
      if (!relationTransformation || !SchemaAST.isTypeLiteral(relationTransformation)) {
        continue;
      }
      const typeIds = SchemaAST.getAnnotation(Constants.TypeIdsSymbol)(relationTransformation).pipe(Option.getOrElse(() => []));
      if (typeIds.length === 0) {
        continue;
      }
      const relationMetadata = relationInfo.find(info => info.typeId === result.value && info.propertyName === String(prop.name));
      // Get relations from aliased field if we have relationInfo for this property, otherwise fallback to old behavior
      let allRelationsWithTheCorrectPropertyTypeId;
      let relationConnection;
      if (relationMetadata) {
        // Use the aliased field to get relations for this specific type ID
        const alias = getRelationAlias(result.value, relationMetadata.targetTypeIds);
        relationConnection = queryEntity[alias];
        if (relationMetadata.includeNodes) {
          allRelationsWithTheCorrectPropertyTypeId = relationConnection?.nodes;
        }
      }
      const relationSchema = Schema.make(relationTransformation);
      const decodeRelation = Schema.decodeUnknownEither(relationSchema);
      if (allRelationsWithTheCorrectPropertyTypeId) {
        for (const relationEntry of allRelationsWithTheCorrectPropertyTypeId) {
          let nestedRawEntity = {
            id: relationEntry.toEntity.id,
            _relation: {
              id: relationEntry.id
            }
          };
          const childConversion = convertRelations(relationEntry.toEntity, relationTransformation, relationMetadata?.children ?? []);
          nestedRawEntity = {
            ...nestedRawEntity,
            ...childConversion.rawEntity
          };
          invalidRelations.push(...childConversion.invalidRelations);
          for (const nestedProp of relationTransformation.propertySignatures) {
            const propType = nestedProp.isOptional && SchemaAST.isUnion(nestedProp.type) ? nestedProp.type.types.find(member => !SchemaAST.isUndefinedKeyword(member)) ?? nestedProp.type : nestedProp.type;
            const nestedResult = SchemaAST.getAnnotation(Constants.PropertyIdSymbol)(propType);
            if (Option.isSome(nestedResult)) {
              const value = relationEntry.toEntity.valuesList?.find(a => a.propertyId === nestedResult.value);
              if (!value) {
                continue;
              }
              const rawValue = convertPropertyValue(value, propType);
              if (rawValue) {
                nestedRawEntity[String(nestedProp.name)] = rawValue;
              }
            }
          }
          const relationPropertiesSchema = SchemaAST.getAnnotation(Constants.RelationPropertiesSymbol)(relationTransformation);
          if (Option.isSome(relationPropertiesSchema)) {
            const relationPropertiesSchemaAst = relationPropertiesSchema.value.ast;
            for (const nestedProp of relationPropertiesSchemaAst.propertySignatures) {
              const propType = nestedProp.isOptional && SchemaAST.isUnion(nestedProp.type) ? nestedProp.type.types.find(member => !SchemaAST.isUndefinedKeyword(member)) ?? nestedProp.type : nestedProp.type;
              const nestedResult = SchemaAST.getAnnotation(Constants.PropertyIdSymbol)(propType);
              if (Option.isSome(nestedResult)) {
                const value = relationEntry.entity.valuesList?.find(a => a.propertyId === nestedResult.value);
                if (value) {
                  const rawValue = convertPropertyValue(value, propType);
                  if (rawValue !== undefined) {
                    nestedRawEntity._relation[String(nestedProp.name)] = rawValue;
                  }
                }
              }
            }
          }
          const decodedRelation = decodeRelation(nestedRawEntity);
          if (Either.isRight(decodedRelation)) {
            rawEntity[String(prop.name)] = [...rawEntity[String(prop.name)], nestedRawEntity];
          } else {
            invalidRelations.push({
              parentEntityId: queryEntity.id,
              propertyName: String(prop.name),
              propertyTypeId: result.value,
              relationId: relationEntry.id,
              relationTypeId: relationEntry.typeId,
              toEntityId: relationEntry.toEntity.id,
              raw: nestedRawEntity,
              error: decodedRelation.left
            });
          }
        }
      }
      if (relationMetadata?.includeTotalCount) {
        rawEntity[`${String(prop.name)}TotalCount`] = relationConnection?.totalCount ?? 0;
      }
    }
  }
  return {
    rawEntity,
    invalidRelations
  };
};
//# sourceMappingURL=convert-relations.js.map