/**
 * UTableEntity column templates. Exported by `@unitybase/adminui-vue` as `columnTemplates` and can be used as
 *
 * @example
// valid usage
const columnTemplates = require('@unitybase/adminui-vue').columnTemplates
// WRONG usage
const helpers = require('@unitybase/adminui-vue/components/UTableEntity/column-template-provider')
 * @module columnTemplates
 * @memberOf module:@unitybase/adminui-vue
 */

const UB = require('@unitybase/ub-pub')
const defaultType = require('./type-definitions/default')
const defaultCellTemplate = require('../controls/UTable/cell-templates/default.vue').default

module.exports = {
  registerTemplate,
  getByColumnAttribute,
  registerDefaultTemplates
}

/**
 * @typedef {object} ColumnDefinition
 * @property {object} settings
 * @property {Vue.Component} template
 * @property {Object<string, UTableColumnFilter>} filters
 */

/** @type {Object<string, ColumnDefinition>} */
const _cellTemplates = {}

/**
 * Register new cell template
 *
 * @param {string} type Type from UBDomain.ubDataTypes ot
 * @param {UTableColumnSettings} settings Column settings
 * @param {Vue.Component} [cellTemplate] Cell template
 * @param {Object<string, UTableColumnFilter>} [filters={}] Filters templates
 */
function registerTemplate ({ type, settings, cellTemplate = defaultCellTemplate, filters = {} }) {
  _cellTemplates[type] = {
    settings: { ...settings },
    template: cellTemplate,
    filters
  }
}

/**
 * Get column definition by an attribute definition
 *
 * @param {object} [attribute]
 * @returns {ColumnDefinition}
 */
function getByColumnAttribute (attribute) {
  const columnTemplate = attribute?.customSettings?.columnTemplate
  const byAttrSettings = _cellTemplates[columnTemplate]
  if (byAttrSettings) {
    return byAttrSettings
  }
  const dataType = attribute?.dataType
  return _cellTemplates[dataType] ?? { ...defaultType }
}

/**
 * Register default filters. Called by adminui-vue.runApp because filter order depends on uiSettings
 * @param {UBConnection} conn
 */
function registerDefaultTemplates (conn) {
  // filter component display filters in order of Object.keys(filters), so we need to register different combination what depends on startWith or contains is first
  if (conn.appConfig.uiSettings.adminUI.defaultFilterForStringAttr === 'contains') {
    registerTemplate({
      type: 'String',
      settings: require('./type-definitions/string'),
      filters: {
        contains: {
          label: 'contains',
          template: require('./filter-templates/string/contains.vue').default
        },
        equal: {
          label: 'equal',
          template: require('./filter-templates/string/equal.vue').default
        },
        startWith: {
          label: 'startWith',
          template: require('./filter-templates/string/startWith.vue').default
        },
        isNull: {
          label: 'isNull',
          template: require('./filter-templates/string/isNull.vue').default
        },
        notIsNull: {
          label: 'notIsNull',
          template: require('./filter-templates/string/notIsNull.vue').default
        }
      }
    })
  } else {
    registerTemplate({
      type: 'String',
      settings: require('./type-definitions/string'),
      filters: {
        startWith: {
          label: 'startWith',
          template: require('./filter-templates/string/startWith.vue').default
        },
        equal: {
          label: 'equal',
          template: require('./filter-templates/string/equal.vue').default
        },
        contains: {
          label: 'contains',
          template: require('./filter-templates/string/contains.vue').default
        },
        isNull: {
          label: 'isNull',
          template: require('./filter-templates/string/isNull.vue').default
        },
        notIsNull: {
          label: 'notIsNull',
          template: require('./filter-templates/string/notIsNull.vue').default
        }
      }
    })
  }

  registerTemplate({
    type: 'Json',
    settings: require('./type-definitions/json')
  })

  registerTemplate({
    type: 'Boolean',
    settings: require('./type-definitions/boolean'),
    filters: {
      isTrue: {
        label: 'Yes',
        template: require('./filter-templates/boolean/isTrue.vue').default
      },
      isFalse: {
        label: 'No',
        template: require('./filter-templates/boolean/isFalse.vue').default
      },
      isNull: {
        label: 'isNull',
        template: require('./filter-templates/boolean/isNull.vue').default
      }
    }
  })

  registerTemplate({
    type: 'Entity',
    settings: require('./type-definitions/entity'),
    filters: {
      equal: {
        label: 'equal',
        template: require('./filter-templates/entity/equal.vue').default
      },
      in: {
        label: 'by_several_value',
        template: require('./filter-templates/entity/oneOf.vue').default
      },
      isNull: {
        label: 'isNull',
        template: require('./filter-templates/entity/isNull.vue').default
      },
      notIsNull: {
        label: 'notIsNull',
        template: require('./filter-templates/entity/notIsNull.vue').default
      },
      notEqual: {
        label: 'notEqual',
        template: require('./filter-templates/entity/notEqual.vue').default
      },
      notIn: {
        label: 'notContains',
        template: require('./filter-templates/entity/notContains.vue').default
      }
    }
  })

  registerTemplate({
    type: 'Many',
    settings: require('./type-definitions/many'),
    filters: {
      in: {
        label: 'by_several_value',
        template: require('./filter-templates/many/oneOf.vue').default
      },
      isNull: {
        label: 'isNull',
        template: require('./filter-templates/many/isNull.vue').default
      },
      notIsNull: {
        label: 'notIsNull',
        template: require('./filter-templates/many/notIsNull.vue').default
      }
    }
  })

  registerTemplate({
    type: 'Enum',
    settings: require('./type-definitions/enum'),
    filters: {
      equal: {
        label: 'equal',
        template: require('./filter-templates/enum/equal.vue').default
      },
      in: {
        label: 'by_several_value',
        template: require('./filter-templates/enum/oneOf.vue').default
      },
      isNull: {
        label: 'isNull',
        template: require('./filter-templates/enum/isNull.vue').default
      },
      notIsNull: {
        label: 'notIsNull',
        template: require('./filter-templates/enum/notIsNull.vue').default
      },
      notEqual: {
        label: 'notEqual',
        template: require('./filter-templates/enum/notEqual.vue').default
      },
      notIn: {
        label: 'notContains',
        template: require('./filter-templates/enum/notContains.vue').default
      }
    }
  })

  const dateFilters = {
    range: {
      label: 'range',
      template: require('./filter-templates/date/range.vue').default
    },
    fromDate: {
      label: 'from_date',
      template: require('./filter-templates/date/fromDate.vue').default
    },
    onDate: {
      label: 'date',
      template: require('./filter-templates/date/onDate.vue').default
    },
    toDate: {
      label: 'to_date',
      template: require('./filter-templates/date/toDate.vue').default
    },
    isNull: {
      label: 'isNull',
      template: require('./filter-templates/date/isNull.vue').default
    },
    notIsNull: {
      label: 'notIsNull',
      template: require('./filter-templates/date/notIsNull.vue').default
    }
  }

  registerTemplate({
    type: 'Date',
    settings: {
      minWidth: 120,
      sortable: true,
      format ({ value }) {
        return UB.formatter.formatDate(value, 'date')
      }
    },
    filters: dateFilters
  })

  registerTemplate({
    type: 'DateTime',
    settings: {
      minWidth: 190, // en: 05/23/2020, 1:14 PM
      sortable: true,
      format ({ value }) {
        return UB.formatter.formatDate(value, 'dateTime')
      }
    },
    filters: dateFilters
  })

  const numberFilter = {
    equal: {
      label: 'equal',
      template: require('./filter-templates/number/equal.vue').default
    },
    more: {
      label: 'more',
      template: require('./filter-templates/number/more.vue').default
    },
    less: {
      label: 'less',
      template: require('./filter-templates/number/less.vue').default
    },
    range: {
      label: 'range',
      template: require('./filter-templates/number/range.vue').default
    },
    isNull: {
      label: 'isNull',
      template: require('./filter-templates/number/isNull.vue').default
    },
    notIsNull: {
      label: 'notIsNull',
      template: require('./filter-templates/number/notIsNull.vue').default
    }
  }

  registerTemplate({
    type: 'ID',
    settings: require('./type-definitions/id'),
    filters: numberFilter
  })

  const NUMBER_SETTINGS = require('./type-definitions/number')
  registerTemplate({
    type: 'BigInt',
    settings: NUMBER_SETTINGS,
    filters: numberFilter
  })

  registerTemplate({
    type: 'Currency',
    settings: {
      ...NUMBER_SETTINGS,
      format: ({ value }) => {
        return UB.formatter.formatNumber(value, 'sum')
      }
    },
    filters: numberFilter
  })

  registerTemplate({
    type: 'Float',
    settings: NUMBER_SETTINGS,
    filters: numberFilter
  })

  registerTemplate({
    type: 'Int',
    settings: NUMBER_SETTINGS,
    filters: numberFilter
  })

  registerTemplate({
    type: 'Document',
    settings: {
      sortable: false
    },
    cellTemplate: require('./cell-templates/document.vue').default
  })

  registerTemplate({
    type: 'Text',
    settings: require('./type-definitions/string'),
    cellTemplate: renderWarning('Text')
  })

  registerTemplate({
    type: 'BLOB',
    settings: require('./type-definitions/string'),
    cellTemplate: renderWarning('BLOB')
  })

  registerTemplate({
    type: 'TimeLog',
    settings: require('./type-definitions/string'),
    cellTemplate: renderWarning('TimeLog')
  })
}

/**
 *
 * @param type
 */
function renderWarning (type) {
  return () => {
    console.warn(`By default type "${type}" is rendered as string. Use with caution because such column can creates large server responses`)
  }
}