// ADempiere-Vue (Frontend) for ADempiere ERP & CRM Smart Business Solution
// Copyright (C) 2017-Present E.R.P. Consultores y Asociados, C.A.
// Contributor(s): Yamel Senih ysenih@erpya.com www.erpya.com
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

// A simple class for make easy lookup for dynamic forms from ADempiere Meta-Data
// note that it can be used for create meta-data for lookups
// Field component: this component is created dinamically from meta-data and can be used for
// many form incluyed Window/Tab/Fields, Process and Smart Browsers
// The aproach for this file is allows define field type manual and allows get metadata from server
// Exists many attributes fro handle behavior of field, the follow is a example:
// General:
// - columnName:
// - name:
// - help
// - inTable:
// - isAdvancedQuery:
// - isMandatory:
// - isMandatoryFromLogic
// - isReadOnly:
// - isDisplayed:
// - isShowedFromUser
// - isActive:
// - isSelectCreated:
// - isAlwaysUpdateable:
// - parentUuid:
// - containerUuid:
// - value:
// Lookup:
// - query:
// - directQuery:
// - tableName:
// Date and Time:
// - isRange
// - vFormat
// - valueTo
// - valueMax
// - valueMin
// Number:
// - isRange
// - valueTo
// - valueMax
// - valueMin
// Text:
// - isEncrypted
// - fieldLength
// Select:
// - isSelectCreated (created from ui for multi-selection)
// - query
// - directQuery
// - tableName
// - displayColumn
// - defaultValue

import { CHAR, DEFAULT_SIZE, TABLE_DIRECT } from '@/utils/ADempiere/references.js'
import { evalutateTypeField, getDefaultValue, getEvaluatedLogics } from '@/utils/ADempiere/dictionaryUtils.js'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
import { getParentFields } from '@/utils/ADempiere/contextUtils.js'
import store from '@/store'

// Create a Field from UUID based on server meta-data
export function createFieldFromDictionary({
  containerUuid,
  uuid,
  columnUuid,
  elementUuid,
  elementColumnName,
  tableName,
  columnName,
  overwriteDefinition
}) {
  let field
  let valueToMatch
  if (uuid) {
    field = store.getters.getFieldFromUuid(uuid)
    valueToMatch = uuid
  } else if (columnUuid) {
    field = store.getters.getFieldFromColumnUuid(columnUuid)
    valueToMatch = columnUuid
  } else if (elementUuid) {
    field = store.getters.getFieldFromElementUuid(elementUuid)
    valueToMatch = elementUuid
  } if (elementColumnName) {
    field = store.getters.getFieldFromElementColumnName(elementColumnName)
    valueToMatch = elementColumnName
  } else if (tableName && columnName) {
    field = store.getters.getFieldFromElementColumnName({
      tableName,
      columnName
    })
    valueToMatch = columnName
  }

  if (isEmptyValue(field)) {
    return new Promise(resolve => {
      store.dispatch('getFieldFromServer', {
        uuid,
        columnUuid,
        elementUuid,
        elementColumnName,
        tableName,
        columnName
      })
        .then(response => {
          const newField = getFactoryFromField({
            containerUuid,
            field: response,
            overwriteDefinition
          })

          resolve(newField)
        }).catch(error => {
          console.warn(`LookupFactory: Get Field (match: ${valueToMatch}) From Server (State) - Error ${error.code}: ${error.message}.`)

          const templateField = createFieldFromDefinition({
            containerUuid,
            columnName,
            definition: {
              uuid,
              columnUuid,
              elementUuid,
              elementColumnName,
              tableName,
              columnName,
              ...overwriteDefinition
            }
          })

          resolve(templateField)
        })
    })
  }
  return new Promise(resolve => {
    const fieldWithStore = getFactoryFromField({
      containerUuid,
      field,
      overwriteDefinition
    })

    resolve(fieldWithStore)
  })
}

// Convert field getted from server to factory
function getFactoryFromField({
  containerUuid,
  field,
  overwriteDefinition = {}
}) {
  const definition = {
    parentFieldsList: field.parentFieldsList || [],
    dependentFieldsList: field.dependentFieldsList || [],
    ...field,
    isDisplayed: true,
    // Overwrite definition
    ...overwriteDefinition
  }

  //  Convert it
  return createFieldFromDefinition({
    containerUuid,
    columnName: definition.columnName,
    definition
  })
}

/**
 * Create a field, it assumed that you define all behavior from source code
 * TODO: Join with generateField function
 */
export function createFieldFromDefinition({
  parentUuid,
  containerUuid,
  columnName,
  panelType = 'form',
  definition = {}
}) {
  if (!isEmptyValue(definition)) {
    if (isEmptyValue(definition.displayType)) {
      definition.displayType = CHAR.id
    } else if (definition.displayType === TABLE_DIRECT.id &&
      isEmptyValue(definition.tableName) &&
      columnName.indexOf('_ID') > 0) {
      definition.tableName = columnName.replace('_ID', '')
    }
    if (isEmptyValue(definition.isActive)) {
      definition.isActive = true
    }
    if (isEmptyValue(definition.isDisplayed)) {
      definition.isDisplayed = true
    }
    if (isEmptyValue(definition.isReadOnly)) {
      definition.isReadOnly = false
    }

    if (isEmptyValue(definition.isMandatory)) {
      definition.isMandatory = false
    }
    if (isEmptyValue(definition.sequence)) {
      definition.sequence = 0
      if (definition.isDisplayed) {
        definition.sequence = 10
      }
    }
  }

  return getFieldTemplate({
    panelType,
    ...definition,
    isShowedFromUser: true,
    isCustomField: true,
    parentUuid,
    containerUuid,
    columnName
  })
}

// Default template for injected fields
export function getFieldTemplate(overwriteDefinition) {
  let displayType = CHAR.id // String reference (10)
  if (!isEmptyValue(overwriteDefinition.displayType)) {
    displayType = overwriteDefinition.displayType
  }

  const componentReference = evalutateTypeField(displayType)

  // set size from displayed, max 24
  let size = DEFAULT_SIZE
  if (!isEmptyValue(componentReference.size)) {
    size = componentReference.size
  }
  // rewrite size default size field
  if (!isEmptyValue(overwriteDefinition.size)) {
    size = overwriteDefinition.size
    delete overwriteDefinition.size
    if (typeof size === 'number') {
      size = {
        xs: size,
        sm: size,
        md: size,
        lg: size,
        xl: size
      }
    }
  }

  const fieldTemplateMetadata = {
    id: 0,
    uuid: '',
    name: '',
    description: '',
    help: '',
    columnName: '',
    displayColumnName: `DisplayColumn_${overwriteDefinition.columnName}`, // key to display column
    fieldGroup: {
      name: '',
      fieldGroupType: ''
    },
    displayType,
    componentPath: componentReference.componentPath,
    size,
    isFieldOnly: false,
    isRange: false,
    isSameLine: false,
    sequence: 0,
    seqNoGrid: 0,
    isIdentifier: 0,
    isKey: false,
    isSelectionColumn: false,
    isUpdateable: true,
    //
    formatPattern: undefined,
    vFormat: undefined,
    value: undefined,
    valueTo: undefined,
    defaultValue: undefined,
    parsedDefaultValue: undefined,
    defaultValueTo: undefined,
    parsedDefaultValueTo: undefined,
    valueType: componentReference.valueType, // value type to convert with gGRPC
    valueMin: undefined,
    valueMax: undefined,
    //
    isDisplayed: false,
    isActive: true,
    isMandatory: false,
    isReadOnly: false,
    isDisplayedFromLogic: undefined,
    isReadOnlyFromLogic: undefined,
    isMandatoryFromLogic: undefined,
    // browser attributes
    callout: undefined,
    isQueryCriteria: false,
    displayLogic: undefined,
    mandatoryLogic: undefined,
    readOnlyLogic: undefined,
    handleFocusGained: false,
    handleFocusLost: false,
    handleKeyPressed: false,
    handleKeyReleased: false,
    handleActionKeyPerformed: false,
    handleActionPerformed: false,
    dependentFieldsList: [],
    reference: {
      tableName: '',
      keyColumnName: '',
      query: '',
      directQuery: '',
      validationCode: '',
      zoomWindows: []
    },
    contextInfo: undefined,
    isShowedFromUser: false,
    isFixedTableColumn: false,
    ...overwriteDefinition
  }

  // get parsed parent fields list
  const parentFieldsList = getParentFields(fieldTemplateMetadata)

  // TODO: Add support to isSOTrxMenu
  const parsedDefaultValue = getDefaultValue({
    ...fieldTemplateMetadata
  })

  let parsedDefaultValueTo
  if (fieldTemplateMetadata.isRange) {
    parsedDefaultValueTo = getDefaultValue({
      ...fieldTemplateMetadata,
      defaultValue: fieldTemplateMetadata.defaultValueTo,
      columnName: `${fieldTemplateMetadata.columnName}_To`,
      elementName: `${fieldTemplateMetadata.elementName}_To`
    })
  }

  // evaluate logics (diplayed, mandatory, readOnly)
  const evaluatedLogics = getEvaluatedLogics({
    ...fieldTemplateMetadata
  })

  return {
    ...fieldTemplateMetadata,
    ...evaluatedLogics,
    parsedDefaultValue,
    parsedDefaultValueTo,
    parentFieldsList
  }
}
