import { ComponentType } from '@defra/forms-model';
import lowerFirst from 'lodash/lowerFirst.js';
import { ComponentCollection } from "./ComponentCollection.js";
import { FormComponent, isFormState } from "./FormComponent.js";
import { deduplicateErrorsByHref, getLocationFieldViewModel } from "./LocationFieldHelpers.js";
import { NumberField } from "./NumberField.js";
import { createLowerFirstExpression } from "./helpers/index.js";
import { messageTemplate } from "../pageControllers/validationOptions.js";
import { convertToLanguageMessages } from "../../../utils/type-utils.js";

// Precision constants
// UK latitude/longitude requires high precision for accurate location (within ~11mm)
const DECIMAL_PRECISION = 7; // 7 decimal places

export class LatLongField extends FormComponent {
  constructor(def, props) {
    super(def, props);
    const {
      name,
      options,
      schema
    } = def;
    const isRequired = options.required !== false;

    // Read schema values from def.schema with fallback defaults
    const latitudeMin = schema?.latitude?.min ?? 49.85;
    const latitudeMax = schema?.latitude?.max ?? 60.859;
    const longitudeMin = schema?.longitude?.min ?? -13.687;
    const longitudeMax = schema?.longitude?.max ?? 1.767;
    const latitudeRequired = 'Enter latitude';
    const longitudeRequired = 'Enter longitude';
    const customValidationMessages = convertToLanguageMessages({
      'number.precision': '{{#label}} must have no more than 7 decimal places',
      'number.unsafe': '{{#label}} must be a valid number'
    });
    const latitudeRangeMessage = `Latitude for ${lowerFirst(this.label)} must be between ${latitudeMin} and ${latitudeMax}`;
    const longitudeRangeMessage = `Longitude for ${lowerFirst(this.label)} must be between ${longitudeMin} and ${longitudeMax}`;
    const latitudeMessages = convertToLanguageMessages({
      ...customValidationMessages,
      'any.required': latitudeRequired,
      'number.base': `Enter a valid latitude for ${lowerFirst(this.label)} like 51.519450`,
      'number.min': latitudeRangeMessage,
      'number.max': latitudeRangeMessage
    });
    const longitudeMessages = convertToLanguageMessages({
      ...customValidationMessages,
      'any.required': longitudeRequired,
      'number.base': `Enter a valid longitude for ${lowerFirst(this.label)} like -0.127758`,
      'number.min': longitudeRangeMessage,
      'number.max': longitudeRangeMessage
    });
    this.collection = new ComponentCollection([{
      type: ComponentType.NumberField,
      name: `${name}__latitude`,
      title: 'Latitude',
      schema: {
        min: latitudeMin,
        max: latitudeMax,
        precision: DECIMAL_PRECISION
      },
      options: {
        required: isRequired,
        optionalText: true,
        classes: 'govuk-input--width-10',
        suffix: '°',
        customValidationMessages: latitudeMessages
      }
    }, {
      type: ComponentType.NumberField,
      name: `${name}__longitude`,
      title: 'Longitude',
      schema: {
        min: longitudeMin,
        max: longitudeMax,
        precision: DECIMAL_PRECISION
      },
      options: {
        required: isRequired,
        optionalText: true,
        classes: 'govuk-input--width-10',
        suffix: '°',
        customValidationMessages: longitudeMessages
      }
    }], {
      ...props,
      parent: this
    }, {
      peers: [`${name}__latitude`, `${name}__longitude`]
    });
    this.options = options;
    this.formSchema = this.collection.formSchema;
    this.stateSchema = this.collection.stateSchema;
  }
  getFormValueFromState(state) {
    const value = super.getFormValueFromState(state);
    return LatLongField.isLatLong(value) ? value : undefined;
  }
  getDisplayStringFromFormValue(value) {
    if (!value) {
      return '';
    }

    // CYA page format: <<latvalue, langvalue>>
    return `${value.latitude}, ${value.longitude}`;
  }
  getDisplayStringFromState(state) {
    const value = this.getFormValueFromState(state);
    return this.getDisplayStringFromFormValue(value);
  }
  getContextValueFromFormValue(value) {
    if (!value) {
      return null;
    }

    // Output format: Latitude: <<entry>>\nLongitude: <<entry>>
    return `Latitude: ${value.latitude}\nLongitude: ${value.longitude}`;
  }
  getContextValueFromState(state) {
    const value = this.getFormValueFromState(state);
    return this.getContextValueFromFormValue(value);
  }
  getViewModel(payload, errors) {
    const viewModel = super.getViewModel(payload, errors);
    return getLocationFieldViewModel(this, viewModel, payload, errors);
  }
  getViewErrors(errors) {
    const allErrors = this.getErrors(errors);
    return deduplicateErrorsByHref(allErrors);
  }
  isState(value) {
    return LatLongField.isLatLong(value);
  }

  /**
   * For error preview page that shows all possible errors on a component
   */
  getAllPossibleErrors() {
    return LatLongField.getAllPossibleErrors();
  }

  /**
   * Static version of getAllPossibleErrors that doesn't require a component instance.
   */
  static getAllPossibleErrors() {
    return {
      baseErrors: [{
        type: 'required',
        template: messageTemplate.required
      }, {
        type: 'latitudeFormat',
        template: createLowerFirstExpression('Enter a valid latitude for {{lowerFirst(#title)}} like 51.519450')
      }, {
        type: 'longitudeFormat',
        template: createLowerFirstExpression('Enter a valid longitude for {{lowerFirst(#title)}} like -0.127758')
      }],
      advancedSettingsErrors: [{
        type: 'latitudeMin',
        template: createLowerFirstExpression('Latitude for {{lowerFirst(#title)}} must be between 49 and 60')
      }, {
        type: 'latitudeMax',
        template: createLowerFirstExpression('Latitude for {{lowerFirst(#title)}} must be between 49 and 60')
      }, {
        type: 'longitudeMin',
        template: createLowerFirstExpression('Longitude for {{lowerFirst(#title)}} must be between -9 and 2')
      }, {
        type: 'longitudeMax',
        template: createLowerFirstExpression('Longitude for {{lowerFirst(#title)}} must be between -9 and 2')
      }]
    };
  }
  static isLatLong(value) {
    return isFormState(value) && NumberField.isNumber(value.latitude) && NumberField.isNumber(value.longitude);
  }
}
//# sourceMappingURL=LatLongField.js.map