import type {
  DecoratorContext,
  DecoratorValidatorCallbacks,
  FunctionContext,
  Model,
  ModelProperty,
  Type,
} from "@typespec/compiler";

export interface HttpPartOptions {
  readonly name?: string;
}

export interface ApplyMergePatchOptions {
  readonly visibilityMode: unknown;
}

export type PlainDataDecorator = (
  context: DecoratorContext,
  target: Model,
) => DecoratorValidatorCallbacks | void;

export type HttpFileDecorator = (
  context: DecoratorContext,
  target: Model,
) => DecoratorValidatorCallbacks | void;

export type HttpPartDecorator = (
  context: DecoratorContext,
  target: Model,
  type: Type,
  options: HttpPartOptions,
) => DecoratorValidatorCallbacks | void;

/**
 * Specify if inapplicable metadata should be included in the payload for the given entity.
 *
 * @param value If true, inapplicable metadata will be included in the payload.
 */
export type IncludeInapplicableMetadataInPayloadDecorator = (
  context: DecoratorContext,
  target: Type,
  value: boolean,
) => DecoratorValidatorCallbacks | void;

/**
 * Performs the canonical merge-patch transformation on the given model and injects its
 * transformed properties into the target.
 */
export type ApplyMergePatchDecorator = (
  context: DecoratorContext,
  target: Model,
  source: Model,
  nameTemplate: string,
  options: ApplyMergePatchOptions,
) => DecoratorValidatorCallbacks | void;

/**
 * Marks a model that was generated by applying the MergePatch
 * transform and links to its source model
 */
export type MergePatchModelDecorator = (
  context: DecoratorContext,
  target: Model,
  source: Model,
) => DecoratorValidatorCallbacks | void;

/**
 * Links a modelProperty mutated as part of a mergePatch transform to
 * its source property;
 */
export type MergePatchPropertyDecorator = (
  context: DecoratorContext,
  target: ModelProperty,
  source: ModelProperty,
) => DecoratorValidatorCallbacks | void;

export type TypeSpecHttpPrivateDecorators = {
  plainData: PlainDataDecorator;
  httpFile: HttpFileDecorator;
  httpPart: HttpPartDecorator;
  includeInapplicableMetadataInPayload: IncludeInapplicableMetadataInPayloadDecorator;
  applyMergePatch: ApplyMergePatchDecorator;
  mergePatchModel: MergePatchModelDecorator;
  mergePatchProperty: MergePatchPropertyDecorator;
};

export type ApplyMergePatchTransformFunctionImplementation = (
  context: FunctionContext,
  input: Model,
  nameTemplate: string,
  options: ApplyMergePatchOptions,
) => Model;

export type TypeSpecHttpPrivateFunctions = {
  applyMergePatchTransform: ApplyMergePatchTransformFunctionImplementation;
};
