import { isArray } from "lodash";
import { ARRAY } from "../../array";
import { FieldMap, Model } from "../../model";
import { DICTIONARY, KnownRecord, RECORD } from "../../record";
import {
  GUID,
  isString
} from "../../string";
import int from "./integer";
import value, { valueArray, valueDictionary } from "./value";

export function recordArray(
  type: string | FieldMap<KnownRecord>,
  count: number,
  models: Record<string, Model>
) {
  const ret: any[] = [];
  for (let i = 0; i < count; i++) {
    ret.push(record(type, models));
  }
  return ret;
}

export function recordDictionary(
  type: string | FieldMap<KnownRecord>,
  count: number,
  models: Record<string, Model>,
  keyType: string = GUID
) {
  const ret = {};
  for (let i = 0; i < count; i++) {
    Object.assign(ret, { [value(keyType)]: record(type, models) });
  }
  return ret;
}

export default function record(
  type: string | FieldMap<KnownRecord>,
  models: Record<string, Model<KnownRecord>>
): object | null {
  const fields = isString(type) ? models[type].fields : type;
  if (!fields) {
    return null;
  }

  return Object.entries(fields).reduce((acc, [key, field]) => {
    if (isString(field.type)) {
      if (field.type === RECORD) {
        return {};
      }
      let val = value(field.type);
      if (typeof val === undefined) {
        val = record(field.type, models);
      }
      return Object.assign(acc, { [key]: val });
    } else if (!isArray(field.type)) {
      return acc;
    }
    const [type, primary, secondary, ...more] = field.type;
    if (!isString(type)) {
      if (primary === ARRAY) {
        const val = recordArray(type, int({ max: 9, min: 2 }), models);
        return Object.assign(acc, { [key]: val });
      } else if (primary === DICTIONARY) {
        const val = recordDictionary(
          type,
          int({ max: 9, min: 2 }),
          models,
          more.shift() || GUID
        );
        return Object.assign(acc, { [key]: val });
      }
      const val = record(type, models);
      return Object.assign(acc, { [key]: val });
    }

    if (primary === RECORD) {
      if (secondary === ARRAY) {
        const val = recordArray(type, int({ max: 9, min: 2 }), models);
        return Object.assign(acc, { [key]: val });
      } else if (secondary === DICTIONARY) {
        const val = recordDictionary(
          type,
          int({ max: 9, min: 2 }),
          models,
          more.shift() || GUID
        );
        return Object.assign(acc, { [key]: val });
      }
      const val = record(type, models);
      return Object.assign(acc, { [key]: val });
    } else if (primary === ARRAY) {
      const val = valueArray(type, int({ max: 9, min: 2 }));
      return Object.assign(acc, { [key]: val });
    } else if (primary === DICTIONARY) {
      const val = valueDictionary(type, int({ max: 9, min: 2 }), secondary || GUID);
      return Object.assign(acc, { [key]: val });
    }
    let val = value(type);
    if (typeof val === undefined) {
      val = record(type, models);
    }

    return Object.assign(acc, { [key]: val });
  }, {});
}
