import { SchemaOptions } from '../decorator/schema.decorator';
import { Type } from '@nestjs/common';

type PropertyOptions<T = any> = {
  required: boolean,
  type: Type,

  default?: T,
  isArray?: boolean,

  size?: number,
  encrypt?: boolean;

  isEmail?: boolean;

  enum?: Record<string, any>;

  isInt?: boolean;
  min?: number;
  max?: number;
};

type Property = {
  target: Function,
  propertyKey: string,
  options: PropertyOptions,
};

type IndexOptions = {
  type: 'key' | 'fulltext' | 'unique';
  orders: ('ASC' | 'DESC')[];
  attributes: string[];
};

type Index = {
  target: Function,
  propertyKey: string,
  options: IndexOptions,
};

class TypeMetadataStorage {
  private readonly schemas: Map<Function, SchemaOptions> = new Map();
  private readonly properties: Property[] = [];
  private readonly indexes: Index[] = [];

  public addSchemaMetadata = (target: Function, options: SchemaOptions): void => {
    this.schemas.set(target, options);
  };

  public getSchemaMetadata = (target: Function): SchemaOptions => {
    const schemaMetadata = this.schemas.get(target);
    if (!schemaMetadata) {
      throw new Error(`Forgot to put Schema decorator for target ${target.name}`);
    }
    return schemaMetadata;
  };

  public addPropertyMetadata = (target: Function, propertyKey: string, options: PropertyOptions): void => {
    this.properties.push({ target, propertyKey, options });
  };

  public getClassProperties = (target: Function): Property[] => {
    return this.properties.filter((property) => property.target === target);
  };

  public addIndexMetadata = (target: Function, propertyKey: string, options: IndexOptions): void => {
    this.indexes.push({ target, propertyKey, options });
  };

  public getClassIndexes = (target: Function): Index[] => {
    return this.indexes.filter((index) => index.target === target);
  };
}

export default new TypeMetadataStorage();
