import { Option, SchemaAST } from "effect";
function getTypeLiteral(ast) {
  switch (ast._tag) {
    case "TypeLiteral":
      return ast;
    case "Transformation":
      return getTypeLiteral(ast.to);
    case "Refinement":
      return getTypeLiteral(ast.from);
    case "Suspend":
      return getTypeLiteral(ast.f());
    default:
      return null;
  }
}
function findPropertySignature(schema, fieldName) {
  const tl = getTypeLiteral(schema.ast);
  if (!tl) return null;
  return tl.propertySignatures.find((p) => p.name === fieldName) ?? null;
}
function resolveFieldType(ps) {
  const t = ps.type;
  if (t._tag === "Union" && ps.isOptional) {
    const nonUndef = t.types.find((m) => m._tag !== "UndefinedKeyword");
    if (nonUndef) return nonUndef;
  }
  return t;
}
function getFieldAnnotation(schema, fieldName, getter) {
  const ps = findPropertySignature(schema, fieldName);
  if (!ps) return void 0;
  const fromPS = getter(ps);
  if (Option.isSome(fromPS)) return fromPS.value;
  const resolved = resolveFieldType(ps);
  const fromResolved = getter(resolved);
  if (Option.isSome(fromResolved)) return fromResolved.value;
  if (resolved !== ps.type) {
    const fromType = getter(ps.type);
    if (Option.isSome(fromType)) return fromType.value;
  }
  return void 0;
}
export function getStructFieldTitle(schema, fieldName) {
  return getFieldAnnotation(schema, fieldName, SchemaAST.getTitleAnnotation);
}
export function getStructFieldDescription(schema, fieldName) {
  return getFieldAnnotation(schema, fieldName, SchemaAST.getDescriptionAnnotation);
}
function getNestedFieldAnnotation(schema, parentField, childField, getter) {
  const parentPs = findPropertySignature(schema, parentField);
  if (!parentPs) return void 0;
  const tl = getTypeLiteral(resolveFieldType(parentPs));
  if (!tl) return void 0;
  const ps = tl.propertySignatures.find((p) => p.name === childField);
  if (!ps) return void 0;
  const fromPS = getter(ps);
  if (Option.isSome(fromPS)) return fromPS.value;
  const resolved = resolveFieldType(ps);
  const fromResolved = getter(resolved);
  if (Option.isSome(fromResolved)) return fromResolved.value;
  if (resolved !== ps.type) {
    const fromType = getter(ps.type);
    if (Option.isSome(fromType)) return fromType.value;
  }
  return void 0;
}
export function getNestedStructFieldTitle(schema, parentField, childField) {
  return getNestedFieldAnnotation(schema, parentField, childField, SchemaAST.getTitleAnnotation);
}
export function getNestedStructFieldDescription(schema, parentField, childField) {
  return getNestedFieldAnnotation(schema, parentField, childField, SchemaAST.getDescriptionAnnotation);
}
export function listStructFields(schema) {
  const tl = getTypeLiteral(schema.ast);
  if (!tl) return [];
  return tl.propertySignatures.map((ps) => {
    const name = String(ps.name);
    const title = getStructFieldTitle(schema, name);
    const description = getStructFieldDescription(schema, name);
    return {
      name,
      ...title !== void 0 ? { title } : {},
      ...description !== void 0 ? { description } : {},
      optional: ps.isOptional
    };
  });
}
