import { DateUtils } from "@sankhyalabs/core";
import { buildFieldMetadata } from "../interfaces/AbstractFieldMetadata";
import { getI18n } from "../i18n";
const DETAIL_PATTERN = /child\[([^\]]+)\]/;
const REGEX_DEFAULT_VAR_KEY = /\$\{.+\}/;
export class FormMetadata {
  constructor() {
    this._sheets = new Map();
    this._requiredFields = [];
    this._cleanOnCopyFields = [];
    this._defaultValues = {};
  }
  static getDetailName(name) {
    const result = DETAIL_PATTERN.exec(name);
    return result ? result[1] : undefined;
  }
  getSheet(name) {
    return this._sheets.get(name);
  }
  getAllSheets() {
    return this._sheets;
  }
  addSheet(sheet) {
    this._sheets.set(sheet.name, sheet);
  }
  addRequiredFields(fields) {
    this._requiredFields = this._requiredFields.concat(fields);
  }
  getRequiredFields() {
    return this._requiredFields;
  }
  addCleanOnCopyFields(fields) {
    this._cleanOnCopyFields = this._cleanOnCopyFields.concat(fields);
  }
  getCleanOnCopyFields() {
    return this._cleanOnCopyFields;
  }
  addDefaultValues(defaultValues) {
    return this._defaultValues = Object.assign(Object.assign({}, this._defaultValues), defaultValues);
  }
  getDefaultValues() {
    const result = {};
    Object.entries(this._defaultValues).forEach(([key, value]) => {
      if (typeof value === "string") {
        const result = REGEX_DEFAULT_VAR_KEY.exec(value);
        if (result) {
          value = this.getDefaultVar(result[0]);
        }
      }
      result[key] = value;
    });
    return result;
  }
  getDefaultVar(name) {
    if (name === "${data}") {
      return DateUtils.getToday();
    }
    if (name === "${datahora}") {
      return DateUtils.getToday(true);
    }
    return this._defaultVars ? this._defaultVars.get(name) : undefined;
  }
  setDefaultVars(vars) {
    this._defaultVars = vars;
  }
}
export const buildFormConfigFromDataUnit = (dataUnit) => {
  const unitMD = dataUnit.metadata;
  let fields;
  if (unitMD) {
    fields = unitMD.fields
      .filter(descriptor => descriptor.visible !== false)
      .map(descriptor => { return { name: descriptor.name, defaultValue: descriptor.defaultValue }; });
  }
  const config = { emptyConfig: false, fields };
  return config;
};
export const buildFormMetadata = (config, dataUnit, includeDetails = false) => {
  var _a, _b;
  if (config == undefined || (config === null || config === void 0 ? void 0 : config.emptyConfig) === true) {
    config = buildFormConfigFromDataUnit(dataUnit);
  }
  const sheets = new Map();
  const hiddenTabs = new Map();
  const requiredFields = [];
  const cleanOnCopyFields = [];
  const defaultValues = {};
  (_a = config === null || config === void 0 ? void 0 : config.tabs) === null || _a === void 0 ? void 0 : _a.forEach((tab) => {
    if (!hiddenTabs.has(tab.label) && tab.visible === false) {
      hiddenTabs.set(tab.label, tab);
    }
  });
  (_b = config === null || config === void 0 ? void 0 : config.fields) === null || _b === void 0 ? void 0 : _b.forEach((field) => {
    var _a, _b, _c;
    if (field.visible !== false) {
      const tabConfig = getTabConfig(field.tab || "__main", sheets, config);
      if (hiddenTabs.has(tabConfig.label)) {
        return;
      }
      const descriptor = dataUnit.getField(field.name);
      const fieldVisible = (descriptor === null || descriptor === void 0 ? void 0 : descriptor.visible) == undefined || (descriptor === null || descriptor === void 0 ? void 0 : descriptor.visible) === true;
      if (descriptor && fieldVisible && tabConfig.visible) {
        if (!sheets.has(tabConfig)) {
          sheets.set(tabConfig, []);
        }
        const formField = buildFieldMetadata(descriptor, field);
        sheets.get(tabConfig).push(formField);
        if (formField.required) {
          requiredFields.push(field.name);
        }
        const cleanOnCopy = field.cleanOnCopy == undefined ? (_a = descriptor.properties) === null || _a === void 0 ? void 0 : _a.cleanOnCopy : field.cleanOnCopy;
        if (cleanOnCopy || ((_b = descriptor.properties) === null || _b === void 0 ? void 0 : _b.cleanOnCopy)) {
          cleanOnCopyFields.push(field.name);
        }
        let defaultValue = field.defaultValue == undefined ? (_c = descriptor.properties) === null || _c === void 0 ? void 0 : _c.defaultValue : field.defaultValue;
        if (defaultValue && defaultValue.value != undefined) {
          const { type, value } = defaultValue;
          if (type) {
            if (type === "V") {
              defaultValue = value;
            }
            else {
              try {
                const parsed = JSON.parse(value);
                if (parsed && "value" in parsed) {
                  defaultValue = parsed;
                }
                else {
                  defaultValue = value;
                }
              }
              catch (_d) { }
            }
          }
          defaultValues[field.name] = defaultValue;
        }
      }
    }
  });
  const metadata = new FormMetadata();
  metadata.setDefaultVars(config.defaultVars);
  if (includeDetails) {
    const unitMD = dataUnit.metadata;
    if (unitMD != undefined && unitMD.children != undefined) {
      unitMD.children.forEach((child) => {
        if (hiddenTabs.has(child.label)) {
          return;
        }
        const tabConfig = getTabFromConfig(child.label, config);
        if (tabConfig) {
          sheets.set(Object.assign(tabConfig, { name: buildChildName(child) }), []);
          return;
        }
        const { label, name, fields } = buildDetailSheet(child);
        sheets.set({ name, label }, fields);
      });
    }
  }
  const i18n = getI18n();
  Array.from(sheets.entries())
    .sort(sortTabs)
    .forEach(([key, fields]) => {
    metadata.addSheet({
      label: (key.label === "__main") ? i18n("ez-form.mainTab") : key.label,
      name: key.name || key.label,
      fields
    });
  });
  metadata.addRequiredFields(requiredFields);
  metadata.addCleanOnCopyFields(cleanOnCopyFields);
  metadata.addDefaultValues(defaultValues);
  return metadata;
};
const getTabFromConfig = (tab, config) => {
  var _a;
  if (!config) {
    return;
  }
  return (_a = config.tabs) === null || _a === void 0 ? void 0 : _a.find(t => t.label === tab);
};
const getTabConfig = (tab, sheets, config) => {
  if (typeof tab !== "string") {
    return tab;
  }
  if (config) {
    const tabConfig = getTabFromConfig(tab, config);
    if (tabConfig) {
      return tabConfig;
    }
  }
  const tabConfig = Array.from(sheets.keys()).find(t => t.label === tab);
  return tabConfig || { label: tab, visible: true };
};
function sortTabs(a, b) {
  var _a, _b;
  if (a[0].label === '__main' && b[0].label !== '__main') {
    return -1;
  }
  if (a[0].label !== '__main' && b[0].label === '__main') {
    return 1;
  }
  const aOrder = (_a = a[0].order) !== null && _a !== void 0 ? _a : Number.MAX_VALUE;
  const bOrder = (_b = b[0].order) !== null && _b !== void 0 ? _b : Number.MAX_VALUE;
  return aOrder - bOrder;
}
const buildChildName = (child) => {
  return `child[${child.name}]`;
};
const buildDetailSheet = (child) => {
  return {
    name: buildChildName(child),
    label: child.label,
    fields: []
  };
};
