/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2026, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////

import _ from 'lodash';
import { isModeSupportedByField } from '../common';
import { FIELD_OPTIONS, booleanEvaluator } from './common';


const COMMON_OPTIONS = '__common';
const _optionEvaluators = { };


export function registerOptionEvaluator(option, evaluator, defaultVal, types) {
  types = types || [COMMON_OPTIONS];
  evaluator = evaluator || booleanEvaluator;
  defaultVal = _.isUndefined(defaultVal) ? false : defaultVal;

  types.forEach((type) => {
    const evaluators = _optionEvaluators[type] =
      (_optionEvaluators[type] || []);

    evaluators.push([option, evaluator, defaultVal]);
  });
}

export function evaluateFieldOption({
  option, schema, value, viewHelperProps, field, options, parentOptions,
}) {
  if (option && option in _optionEvaluators) {
    const evaluators = _optionEvaluators[option];
    evaluators?.forEach(([option, evaluator, defaultVal]) => {
      options[option] = evaluator({
        schema, field, option, value, viewHelperProps, options, defaultVal,
        parentOptions
      });
    });
  }
}

export function evaluateFieldOptions({
  schema, value, viewHelperProps, field, options={}, parentOptions=null
}) {
  evaluateFieldOption({
    option: COMMON_OPTIONS, schema, value, viewHelperProps, field, options,
    parentOptions
  });
  evaluateFieldOption({
    option: field.type, schema, value, viewHelperProps, field, options,
    parentOptions
  });
}

export function schemaOptionsEvalulator({
  schema, data, accessPath=[], viewHelperProps, options, parentOptions=null,
  inGrid=false
}) {
  schema?.fields?.forEach((field) => {
    // We could have multiple entries of same `field.id` for each mode, hence -
    // we should process the options only if the current field is support for
    // the given mode.
    if (!isModeSupportedByField(field, viewHelperProps)) return;

    switch (field.type) {
    case 'nested-tab':
    case 'nested-fieldset':
    case 'inline-groups':
      {
        if (!field.schema) return;
        if (!field.schema.top) field.schema.top = schema.top || schema;

        const path = field.id ? [...accessPath, field.id] : accessPath;

        schemaOptionsEvalulator({
          schema: field.schema, data, path, viewHelperProps, options,
          parentOptions
        });
      }

      break;

    case 'collection':
      {
        if (!field.schema) return;
        if (!field.schema.top) field.schema.top = schema.top || schema;

        const fieldPath = [...accessPath, field.id];
        const fieldOptionsPath = [...fieldPath, FIELD_OPTIONS];
        const fieldOptions = _.get(options, fieldOptionsPath, {});
        const rows = data[field.id];

        evaluateFieldOptions({
          schema, value: data, viewHelperProps, field,
          options: fieldOptions, parentOptions,
        });

        _.set(options, fieldOptionsPath, fieldOptions);

        rows?.forEach((row, idx) => {
          const schemaPath = [...fieldPath, idx];
          const schemaOptions = _.get(options, schemaPath, {});

          _.set(options, schemaPath, schemaOptions);

          schemaOptionsEvalulator({
            schema: field.schema, data: row, accessPath: [],
            viewHelperProps, options: schemaOptions,
            parentOptions: fieldOptions, inGrid: true
          });

          const rowPath = [...schemaPath, FIELD_OPTIONS];
          const rowOptions = _.get(options, rowPath, {});
          _.set(options, rowPath, rowOptions);

          evaluateFieldOption({
            option: 'row', schema: field.schema, value: row, viewHelperProps,
            field, options: rowOptions, parentOptions: fieldOptions
          });
        });

      }
      break;

    default:
      {
        const fieldPath = [...accessPath, field.id];
        const fieldOptionsPath = [...fieldPath, FIELD_OPTIONS];
        const fieldOptions = _.get(options, fieldOptionsPath, {});

        evaluateFieldOptions({
          schema, value: data, viewHelperProps, field, options: fieldOptions,
          parentOptions,
        });

        if (inGrid) {
          evaluateFieldOption({
            option: 'cell', schema, value: data, viewHelperProps, field,
            options: fieldOptions, parentOptions,
          });
        }

        _.set(options, fieldOptionsPath, fieldOptions);
      }
      break;
    }
  });
}
