/* eslint-disable @typescript-eslint/no-explicit-any */

import { CircularProgress } from '@mui/material'
import { Form, Formik } from 'formik'
import _identity from 'lodash/identity'
import _map from 'lodash/map'
import React, { useEffect, useMemo, useState } from 'react'
import { Tooltip } from 'react-tooltip'

import { getAddons, getCart } from '../../api'
import { FEES_STYLES } from '../../constants'
import { currencyNormalizerCreator } from '../../normalizers'
import { CONFIGS, createMarkup } from '../../utils'
import InfoIcon from '../ticketsContainer/InfoIcon'
import { addonsWithGroupsAdapter, cartAdapter } from './adapters'
import AddonComponent from './AddonComponent'
import { getNormalizedPrice } from './normalizers'
import {
  generateSelectOptions,
  getAddonSelectOptions,
  getSortedAddons,
  getTicketRelatedAddons,
} from './utils'

export interface ISimpleAddonContainerProps {
  classNamePrefix?: string;
  onGetAddonsPageInfoSuccess?: (res: any) => void;
  onGetAddonsPageInfoError?: (error: any) => void;
  descriptionTrigger?: 'click' | 'hover' | 'always';
  addOnDataWithCustomFields: any;
  configs: any;
  eventId: string;
  useStepperQty?: boolean;
  maxTotalQuantity?: number;
  addonMaxQuantityGroups?: number;
  onAddOnSelect?: (id: string, value: string, addon: any, fieldUpdates: any) => void;
  handleConfirm?: (values: any) => void;
}

export interface ObjectLiteral {
  [key: string]: any;
}

export const SimpleAddonsContainer = ({
  classNamePrefix = 'add_on',
  onGetAddonsPageInfoSuccess = _identity,
  onGetAddonsPageInfoError = _identity,
  descriptionTrigger = 'click',
  addOnDataWithCustomFields,
  configs,
  eventId,
  useStepperQty = false,
  addonMaxQuantityGroups,
  onAddOnSelect = _identity,
  handleConfirm = _identity,
}: ISimpleAddonContainerProps) => {
  const [addons, setAddons] = useState<any>(null)
  const [addonsOptions, setAddonsOptions] = useState<any>({})
  const [groupsWithSelectedVariants, setGroupsWithSelectedVariants] = useState<any>({})
  const [groupsWithInitialVariantsValues, setGroupsWithInitialVariantsValues] =
    useState<any>({})
  const [crossGroupSelections, setCrossGroupSelections] = useState<ObjectLiteral>({})
  const [loading, setLoading] = useState(true)

  const [visibleDescription, setVisibleDescription] = useState<string | null>(null)

  const handleDescriptionToggle = (ticketId: string) => {
    setVisibleDescription(current => (current === ticketId ? null : ticketId))
  }

  // build { [fieldName]: value } for one addon from current Formik values
  const collectAddonFieldUpdates = (addon: any, allValues: Record<string, any>) => {
    const out: Record<string, any> = {}
    if (!addOnDataWithCustomFields?.fields?.length) return out
    addOnDataWithCustomFields.fields.forEach((group: any) => {
      group.groupItems.forEach((item: any) => {
        const k = `${addon.id}-${group.id}-${item.name}`
        if (k in allValues) out[item.name] = allValues[k]
      })
    })
    return out
  }

  // live-sync a single custom field change into localStorage.add_on_data_capture
  const handleCustomFieldChange = (
    addon: any,
    _groupId: string | number,
    fieldName: string,
    value: any
  ) => {
    const existing = JSON.parse(localStorage.getItem('add_on_data_capture') || '{}')
    const addonId = String(addon.id)
    const next = {
      ...existing,
      [addonId]: { ...(existing[addonId] || {}), [fieldName]: value },
    }
    localStorage.setItem('add_on_data_capture', JSON.stringify(next))
  }

  useEffect(() => {
    const getAddonsPageInfo = async () => {
      try {
        if (eventId) {
          setLoading(true)

          // Get choosed ticket info (id, count) from Cart request for addons options calculations
          const cart = await getCart()
          const { id: choosedTicketID, quantity } = cartAdapter(cart)
          const choosedTicketCount = Number(quantity)

          // Get and collect addons data
          const addonsData = await getAddons(eventId)
          const adaptedAddons = addonsWithGroupsAdapter(addonsData)
          const ticketRelatedAddons = getTicketRelatedAddons(
            adaptedAddons,
            choosedTicketID
          )
          const sortedTicketAddons = getSortedAddons(ticketRelatedAddons)

          setAddons(sortedTicketAddons)

          // Collect addons and addon group options
          const {
            addonsWithOptions,
            groupsWithSelectedVariantsInfo,
            groupsWithVariants,
          } = getAddonSelectOptions(adaptedAddons, choosedTicketCount)

          setAddonsOptions(addonsWithOptions)
          setGroupsWithSelectedVariants(groupsWithSelectedVariantsInfo)
          setGroupsWithInitialVariantsValues(groupsWithVariants)

          // Success callback props
          onGetAddonsPageInfoSuccess(addonsData)
        }
      } catch (e) {
        // Callback error props
        onGetAddonsPageInfoError(e)
      } finally {
        setLoading(false)
      }
    }

    getAddonsPageInfo()
  }, [eventId, onGetAddonsPageInfoError, onGetAddonsPageInfoSuccess])

  const recreateGroupVariantsSelectOptions = (groupId: any, changedGroupd: any) => {
    const { choosedVariants, limit, selectedCount } = changedGroupd
    const remainingGroupStock = limit - selectedCount
    const recreatedVariantsOptions: ObjectLiteral = {}

    // Regenerate variants allowed stock counts
    for (const variant in choosedVariants) {
      const variantId = variant
      const variantCurrSelectedValue = choosedVariants[variant]
      let allowedOptionCount

      // Formula for regenerating
      if (
        remainingGroupStock >=
        groupsWithInitialVariantsValues[groupId][variantId] - variantCurrSelectedValue
      ) {
        allowedOptionCount = groupsWithInitialVariantsValues[groupId][variantId]
      } else {
        allowedOptionCount = remainingGroupStock + variantCurrSelectedValue
      }

      recreatedVariantsOptions[variantId] = generateSelectOptions(0, allowedOptionCount)
    }

    setAddonsOptions((prevState: any) =>
      Object.assign({}, prevState, recreatedVariantsOptions)
    )
  }

  const onFieldChange = (id: any, value: any, addon: any) => {
    // If changeableGroup exsists it means that group with limitation variant was changed
    const changeableGroup = groupsWithSelectedVariants[addon.id]

    if (changeableGroup) {
      const currGroupId = addon.id
      const currSelectedVariantId = id
      const currSelectedVariantCount = Number(value)
      const currSelectedVariantPrevCount =
        groupsWithSelectedVariants[currGroupId].choosedVariants[currSelectedVariantId]

      const currSelectedGroupCount =
        changeableGroup.selectedCount +
        (currSelectedVariantCount - currSelectedVariantPrevCount)

      // Update Group info
      const updatedGroupsWithSelectedVariants = {
        ...groupsWithSelectedVariants,
        [currGroupId]: {
          ...groupsWithSelectedVariants[currGroupId],
          selectedCount: currSelectedGroupCount,
          choosedVariants: {
            ...groupsWithSelectedVariants[currGroupId].choosedVariants,
            [currSelectedVariantId]: currSelectedVariantCount,
          },
        },
      }
      setGroupsWithSelectedVariants(updatedGroupsWithSelectedVariants)

      // Recreate Select Options for Addon Group Variants
      recreateGroupVariantsSelectOptions(
        currGroupId,
        updatedGroupsWithSelectedVariants[currGroupId]
      )
    }
  }

  // Cross-group cap: when addonMaxQuantityGroups is set, limits total selections
  // across ALL addon groups to that number by capping each stepper's max.
  const effectiveAddonsOptions = useMemo(() => {
    if (!addonMaxQuantityGroups) return addonsOptions

    const totalSelected = Object.values(crossGroupSelections).reduce(
      (sum: number, v: any) => sum + Number(v), 0
    )
    const globalRemaining = addonMaxQuantityGroups - totalSelected
    const result: ObjectLiteral = {}

    for (const id in addonsOptions) {
      const opts = addonsOptions[id] || []
      const sdkMax = opts.length ? opts[opts.length - 1].value : 0
      const currSelected = Number(crossGroupSelections[id] || 0)
      const allowedMax = Math.max(0, Math.min(sdkMax, globalRemaining + currSelected))
      result[id] = opts.filter((opt: any) => opt.value <= allowedMax)
    }

    return result
  }, [addonsOptions, crossGroupSelections, addonMaxQuantityGroups])

  const handleCrossGroupChange = (id: any, value: any) => {
    if (addonMaxQuantityGroups) {
      setCrossGroupSelections((prev: ObjectLiteral) => ({ ...prev, [id]: Number(value) }))
    }
  }

  const initialValues = useMemo(() => {
    const addOnsData: any = {}
    if (addons?.length > 0 && addOnDataWithCustomFields?.fields?.length > 0) {
      _map(addons, addon => {
        _map(addOnDataWithCustomFields.fields, field => {
          const { id, groupItems } = field
          _map(groupItems, item => {
            addOnsData[`${addon.id}-${id}-${item.name}`] = item.value
          })
        })
      })
    }

    return addOnsData
  }, [addons, addOnDataWithCustomFields])

  if (loading || !addons) {
    return (
      <div className={`${classNamePrefix}_loader`}>
        <CircularProgress size={50} />
      </div>
    )
  }

  return (
    <div className={`${classNamePrefix}_container`}>
      <div className={`${classNamePrefix}_block`}>
        <div className={`${classNamePrefix}_line_block`}>
          {addons?.length > 0 && (
            <div className={`${classNamePrefix}_title`}>UPGRADES & ADD-ONS</div>
          )}
        </div>
        {addons?.length > 0 && (
          <div className={`${classNamePrefix}_subtitle`}>
            PLEASE SELECT FROM THE OPTIONAL ADD-ONS BELOW
          </div>
        )}
        <Formik
          initialValues={initialValues}
          onSubmit={values => {
            handleConfirm(values)
          }}
          validate={() => {
            // Real-time validation can be handled here if needed
          }}
        >
          {({ values, errors, setFieldTouched }) => {
            return (
            <Form autoComplete="off" className="form_holder">
              <>
                {addons.map((addon: any) => {
                  const price = addon.feeIncluded ? addon.price : addon.cost
                  const isAddonFree = Number(addon?.price) === 0

                  const addOnNormalizedCost = isAddonFree
                    ? 'FREE'
                    : currencyNormalizerCreator(
                        getNormalizedPrice(addon?.cost ?? 0),
                        addon.currency
                      )

                  const addonNormalizedPrice = isAddonFree
                    ? 'FREE'
                    : currencyNormalizerCreator(
                        getNormalizedPrice(
                          CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH
                            ? addon?.price ?? price
                            : price
                        ),
                        addon.currency
                      )

                  return (
                    <div key={addon.id} className={`${classNamePrefix}_product_block`}>
                      <div className={`${classNamePrefix}_product_images`}>
                        {addon.imageUrl && (
                          <div className={`${classNamePrefix}_product_image_block`}>
                            <img src={addon.imageUrl} alt="No Data" />
                          </div>
                        )}
                      </div>
                      <div className={`${classNamePrefix}_product_info_block`}>
                        <div className={`${classNamePrefix}_product_title`}>
                          {addon.name}
                          {addon.description && descriptionTrigger !== 'always' && (
                            <>
                              <span
                                aria-hidden
                                className="info-icon"
                                onClick={
                                  descriptionTrigger === 'click'
                                    ? () => handleDescriptionToggle(addon.id)
                                    : undefined
                                }
                                onMouseEnter={
                                  descriptionTrigger === 'hover'
                                    ? () => setVisibleDescription(addon.id)
                                    : undefined
                                }
                                onMouseLeave={
                                  descriptionTrigger === 'hover'
                                    ? () => setVisibleDescription(null)
                                    : undefined
                                }
                                style={{
                                  marginLeft: 8,
                                  cursor: 'pointer',
                                  display: 'flex',
                                }}
                                data-tooltip-id={`tooltip-${addon.id}`}
                                data-tooltip-content="View Add-On info"
                              >
                                <InfoIcon size={14} />
                              </span>
                              <Tooltip id={`tooltip-${addon.id}`} place="top">
                                {addon.description || 'No description available'}
                              </Tooltip>
                            </>
                          )}
                        </div>
                        <div className={`${classNamePrefix}_product_price`}>
                          {CONFIGS.FEES_STYLE === FEES_STYLES.TRADITIONAL
                            ? addonNormalizedPrice
                            : addOnNormalizedCost}
                          {!isAddonFree &&
                            CONFIGS.FEES_STYLE === FEES_STYLES.TRADITIONAL && (
                              <span className={`${classNamePrefix}_product_fee`}>
                                {addon.feeIncluded ? '(incl. Fees)' : '(excl. Fees)'}
                              </span>
                            )}
                          {!isAddonFree &&
                            CONFIGS.FEES_STYLE === FEES_STYLES.DISPLAY_BOTH && (
                              <>
                                <span className={`${classNamePrefix}_product_fee`}>
                                  {`(${addonNormalizedPrice} with fees)`}
                                </span>
                              </>
                            )}
                        </div>
                      </div>
                      {(visibleDescription === addon.id ||
                        descriptionTrigger === 'always') && (
                        <div
                          className={`${classNamePrefix}_product_desc`}
                          dangerouslySetInnerHTML={createMarkup(addon.description)}
                        />
                      )}
                      <div className={`${classNamePrefix}_product_select_container`}>
                        {addon.variants ? (
                          addon.variants.map((variant: any) => (
                            // Group Variants
                            <AddonComponent
                              key={variant.id}
                              data={variant}
                              selectOptions={effectiveAddonsOptions[variant.id]}
                              classNamePrefix={classNamePrefix}
                              siblingIds={addon.variants.filter((v: any) => v.id !== variant.id).map((v: any) => v.id)}
                              handleAddonChange={(id, value) => {
                                handleCrossGroupChange(id, value)
                                onFieldChange(id, value, addon)
                                const fieldUpdates = collectAddonFieldUpdates(
                                  addon,
                                  values
                                )
                                onAddOnSelect(id, value, addon, fieldUpdates)
                              }}
                              onCustomFieldChange={handleCustomFieldChange}
                              addOnDataWithCustomFields={addOnDataWithCustomFields}
                              configs={configs}
                              values={values}
                              errors={errors}
                              useStepperQty={useStepperQty}
                            />
                          ))
                        ) : (
                          // Simple Addon
                          <AddonComponent
                            key={addon.id}
                            data={addon}
                            selectOptions={effectiveAddonsOptions[addon.id]}
                            classNamePrefix={classNamePrefix}
                            handleAddonChange={(id, value) => {
                              handleCrossGroupChange(id, value)
                              onFieldChange(id, value, addon)
                              const fieldUpdates = collectAddonFieldUpdates(addon, values)
                              onAddOnSelect(id, value, addon, fieldUpdates)
                              _map(addOnDataWithCustomFields.fields, fieldGroup => {
                                const { id, groupItems } = fieldGroup
                                _map(groupItems, field => {
                                  setFieldTouched(
                                    `${addon.id}-${id}-${field.name}`,
                                    true,
                                    true
                                  )
                                })
                              })
                            }}
                            onCustomFieldChange={handleCustomFieldChange}
                            addOnDataWithCustomFields={addOnDataWithCustomFields}
                            configs={configs}
                            values={values}
                            errors={errors}
                            useStepperQty={useStepperQty}
                          />
                        )}
                      </div>
                    </div>
                  )
                })}
              </>
            </Form>
          )}}
        </Formik>
      </div>
    </div>
  )
}

export default SimpleAddonsContainer
