/* eslint-disable @typescript-eslint/no-explicit-any */
import { Field, useFormikContext } from 'formik'
import _identity from 'lodash/identity'
import _isEmpty from 'lodash/isEmpty'
import _isNull from 'lodash/isNull'
import _map from 'lodash/map'
import React from 'react'

import {
  getFieldComponent,
  getFieldLabel,
  getValidateFunctions,
} from '../billing-info-container/utils'
import { NativeSelectField } from '../common'

interface IAddonComponentProps {
  classNamePrefix: string;
  data: any;
  selectOptions: any;
  handleAddonChange?: (...res: any) => void;
  addOnDataWithCustomFields: any;
  configs: any;
  values: any;
  errors: any;
  useStepperQty?: boolean;
  siblingIds?: string[];
  allAddonIds?: string[];
  maxTotalQuantity?: number;
  onCustomFieldChange?: (
    addon: any,
    groupId: string | number,
    fieldName: string,
    value: any
  ) => void;
}

const AddonStepper = ({ id, selectOptions, handleAddonChange, classNamePrefix, siblingIds = [], allAddonIds = [], maxTotalQuantity }: any) => {
  const { values, setFieldValue } = useFormikContext<any>()
  const qty = Number(values[id] ?? 0)
  const max = selectOptions?.length > 0 ? selectOptions[selectOptions.length - 1].value : 0

  const totalSelected = allAddonIds.length > 0
    ? allAddonIds.reduce((sum: number, aid: string) => sum + Number(values[aid] ?? 0), 0)
    : 0

  const change = (next: number) => {
    if (next > qty) {
      if (maxTotalQuantity != null) {
        allAddonIds.forEach((aid: string) => { if (aid !== id) setFieldValue(aid, 0) })
      } else {
        siblingIds.forEach((siblingId: string) => setFieldValue(siblingId, 0))
      }
    }
    setFieldValue(id, next)
    handleAddonChange(id, next)
  }

  const incrementDisabled = qty >= max || (maxTotalQuantity != null && totalSelected >= maxTotalQuantity && qty === 0)

  return (
    <div className={`${classNamePrefix}_stepper`}>
      <button
        type="button"
        className={`${classNamePrefix}_stepper__btn`}
        onClick={() => change(qty - 1)}
        disabled={qty <= 0}
        aria-label="Decrease quantity"
      >
        −
      </button>
      <span className={`${classNamePrefix}_stepper__count`}>{qty}</span>
      <button
        type="button"
        className={`${classNamePrefix}_stepper__btn`}
        onClick={() => change(qty + 1)}
        disabled={incrementDisabled}
        aria-label="Increase quantity"
      >
        +
      </button>
    </div>
  )
}

const AddonComponent = ({
  classNamePrefix = '',
  data,
  selectOptions,
  handleAddonChange = _identity,
  addOnDataWithCustomFields,
  configs,
  values,
  errors,
  useStepperQty = false,
  siblingIds = [],
  allAddonIds = [],
  maxTotalQuantity,
  onCustomFieldChange = _identity,
}: IAddonComponentProps) => {
  const { id, name, active, stock } = data

  return (
    <div key={id} className={`${classNamePrefix}_product_select_container`}>
      <div className={`${classNamePrefix}_product_select_block`} key={name}>
        {!useStepperQty && <div className={`${classNamePrefix}_product_size`}>{name}</div>}
        <div className={`${classNamePrefix}_product_qty_select_block`}>
          {!active || (!_isNull(stock) && stock <= 0) ? (
            <div className={`${classNamePrefix}_stepper_row`}>
              <span className={`${classNamePrefix}_stepper_label`}>{name}</span>
              <div className="sold_out">SOLD OUT</div>
            </div>
          ) : (
            <>
              <div className={`${classNamePrefix}_product_qty_select`}>
                {useStepperQty ? (
                  <div className={`${classNamePrefix}_stepper_row`}>
                    <span className={`${classNamePrefix}_stepper_label`}>{name}</span>
                    <AddonStepper
                      id={id}
                      selectOptions={selectOptions}
                      handleAddonChange={handleAddonChange}
                      classNamePrefix={classNamePrefix}
                      siblingIds={siblingIds}
                      allAddonIds={allAddonIds}
                      maxTotalQuantity={maxTotalQuantity}
                    />
                  </div>
                ) : (
                  <Field
                    name={id}
                    selectOptions={selectOptions}
                    component={NativeSelectField}
                    onChange={(e: any) => {
                      const { value } = e.target
                      handleAddonChange(id, value)
                    }}
                  />
                )}
              </div>
              {!_isEmpty(addOnDataWithCustomFields?.fields) && values[id] > 0 && (
                <div className="add-on-fields">
                  <h2>{addOnDataWithCustomFields.label}</h2>
                  {_map(addOnDataWithCustomFields.fields, group => {
                    const { id, groupClassname, groupItems } = group
                    return (
                      <div key={id}>
                        <div className={groupClassname}>
                          {_map(groupItems, element => {
                            const fieldName = `${data.id}-${id}-${element.name}`
                            const Comp = getFieldComponent(element)
                            const type =
                              element.type === 'radio' || element.type === 'checkbox'
                                ? undefined
                                : element.type
                            return (
                              <div className={element.className} key={fieldName}>
                                <Field
                                  {...element}
                                  name={fieldName}
                                  validate={getValidateFunctions(
                                    element,
                                    [],
                                    values,
                                    errors
                                  )}
                                >
                                  {({ field, form }: any) => {
                                    const handleChange = (e: any) => {
                                      // extract value from native events or custom widgets
                                      const v = e?.target?.value ?? e?.value ?? e // allow custom components to pass raw value
                                      form.setFieldValue(field.name, v)
                                      onCustomFieldChange?.(data, id, element.name, v)
                                    }

                                    return (
                                      <Comp
                                        {...element}
                                        field={field}
                                        form={form}
                                        type={type}
                                        label={getFieldLabel(element, configs)}
                                        onChange={handleChange}
                                      />
                                    )
                                  }}
                                </Field>
                              </div>
                            )
                          })}
                        </div>
                      </div>
                    )
                  })}
                </div>
              )}
            </>
          )}
        </div>
      </div>
    </div>
  )
}

export default AddonComponent
