import { Text, View } from '@tarojs/components'
import { nextTick } from '@tarojs/taro'
import type { FC } from 'react'
import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState, useTransition } from 'react'
import classnames from 'classnames'
import classNames from 'classnames'
import produce, { setAutoFreeze } from 'immer'
import ColorKindItem from '../colorKindItem'
import { selectList } from '../../config'
import type { Goods, GoodsMeta, ShoppingStateContextValue } from '../../context'
import { ShoppingDispatchType, useShoppingDispatch, useShoppingState } from '../../context'
import type { ShoppingStore } from '../../context/shoppingStore'
import { events } from '../../context/shoppingStore'
import styles from './index.module.scss'
import { formatMeterDiv } from '@/common/format'
import LayoutBlock from '@/components/layoutBlock'
import Tag from '@/components/tag'
import Divider from '@/components/divider'
import { EnumSaleMode } from '@/common/Enumerate'
import IconFont from '@/components/iconfont/iconfont'
import { alert, isEmptyObject } from '@/common/common'
import LoadingCard from '@/components/loadingCard'
import { ShoppingCartListApi } from '@/api'
import { usePropsValue } from '@/use/useCommon'

enum BackEndSaleModeListFieldMap {
  bulk_color_list = 0,
  length_cut_color_list = 1,
  weight_cut_color_list = 2,
}
interface ButtonPropsType {
  isActive: boolean
  onClick?: Function
  children?: React.ReactNode
  customStyle?: React.CSSProperties
}
type OperationType = 'add' | 'delete'
// 订单类型
const SaleModeButton: FC<ButtonPropsType> = (props) => {
  const { onClick, children, isActive = false, customStyle } = props
  const handleClick = () => {
    onClick?.()
  }
  return (
    <View className={classnames(styles.saleModeButton, isActive && styles['saleModeButton--active'])} style={customStyle} onClick={handleClick}>
      <View className={classnames(styles['saleModeButton--text'])}>{children}</View>
    </View>
  )
}

const DrawerButton = ({ isOpen }: { isOpen: boolean }) => {
  return (
    <View className={styles.drawerButton}>
      {isOpen ? <IconFont name="icon-shouqi" size={52}></IconFont> : <IconFont name="icon-zhankai" size={52}></IconFont>}
    </View>
  )
}
const DrawerButtonWithMemo = memo(DrawerButton)

interface GoodsListPropType {
  itemData?: ShoppingCartData
  multipleSelection?: GoodsMeta['multipleSelection']
  selected: EnumSaleMode
  isPending: boolean
  startTransition: React.TransitionStartFunction
}
const GoodsList = (props: GoodsListPropType) => {
  const { itemData, selected, isPending, startTransition, multipleSelection } = props
  const prevMultipleSelection = useRef(multipleSelection)
  const currentSelected = useRef<EnumSaleMode | null>(null)

  const dispatch = useShoppingDispatch()

  const [component, setComponent] = useState<JSX.Element | null>(null)
  // 使用 produce 更新特定的 ColorKindItem
  const updateSpecifiedComponent = () => {
    let newId
    if (multipleSelection && prevMultipleSelection.current !== multipleSelection) {
      for (const key in multipleSelection) {
        if (!prevMultipleSelection.current?.hasOwnProperty(key)) {
          newId = key
          break
        }
      }
    }
    console.log('multipleSelection==+>', multipleSelection)
    console.log('currentSelected', currentSelected.current, selected)
    console.log('component', component)
    if (component) {
      if (itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0) {
        setComponent(produce(component, (draft) => {
          console.log('prev', component)
          const index = (draft as unknown as any[]).findIndex(item => item.key === newId)
          console.log('index', index)
          if (index !== -1) {
            const item = itemData?.[BackEndSaleModeListFieldMap[selected]].find((item) => {
              return item.id === Number(newId)
            })
            console.log('item', item, newId)
            draft![index] = <ColorKindItem checked={multipleSelection?.hasOwnProperty(newId)} purchaserId={itemData?.purchaser_id} key={newId} itemData={item}></ColorKindItem>
          }
        }))
      }
      else {
        setComponent(<View className={styles.noList}>暂无数据</View>)
      }
    }
    prevMultipleSelection.current = multipleSelection
  }
  // 更新 GoodsList 组件
  const updateComponent = () => {
    setComponent(
      () => itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0
        ? (
          itemData?.[BackEndSaleModeListFieldMap[selected]].map((item) => {
            console.log('item===>', item, multipleSelection?.hasOwnProperty(item.id))
            return <ColorKindItem checked={multipleSelection?.hasOwnProperty(item.id)} purchaserId={itemData.purchaser_id} key={item.id} itemData={item}></ColorKindItem>
          })
        )
        : (
          <View className={styles.noList}>暂无数据</View>
        ),
    )
    prevMultipleSelection.current = multipleSelection
  }

  useEffect(() => {
    const newGoodsKind = Object.fromEntries(
      itemData?.[BackEndSaleModeListFieldMap[selected]].map(item => [
        item?.id,
        {
          id: item?.id,
          estimate_amount: item.estimate_amount,
          product_code: item.product_code,
          product_color_code: item.product_color_code,
          sale_mode: item.sale_mode,
          count: selected === EnumSaleMode.Bulk ? item.roll : Number(formatMeterDiv(item.length)),
        },
      ]),
    )
    // 这里做一层比较是为了 重新渲染的时候如果没有切换订单类型的话就不让面料的选中状态初始化
    if (currentSelected.current === selected) {
      dispatch({
        type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
        data: {
          purchaserId: itemData?.purchaser_id as number,
          goodsKind: newGoodsKind,
          multipleSelection,
        },
      })
      updateComponent()
    }
    else {
      currentSelected.current = selected
      // 重新把当前的选中状态赋值给ref 作为下一次比较的旧状态
      dispatch({
        type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
        data: {
          purchaserId: itemData?.purchaser_id as number,
          goodsKind: newGoodsKind,
          multipleSelection: {},
        },
      })
      startTransition(updateComponent)
    }
  }, [itemData, selected, multipleSelection])

  return (
    <>
      {isPending
        ? (
          <View className={styles.noList} style={{ margin: '60rpx 0' }}>
            <LoadingCard />
          </View>
        )
        : (
          component
        )}
    </>
  )
}
const GoodsListWithMemo = memo<GoodsListPropType>(GoodsList)

interface PropsType {
  itemData?: ShoppingCartData
  state?: {
    multipleSelection?: GoodsMeta['multipleSelection']
    currentCheckedPurchaserId?: number
    Observer?: ShoppingStore
  }
}

const ShoppingCartItem: FC<PropsType> = (props) => {
  const { state } = props
  console.log('rerender component ShoppingCartItem', props)

  const [itemData, setItemData] = usePropsValue({
    value: props.itemData,
    defaultValue: props.itemData,
  })
  const { multipleSelection, currentCheckedPurchaserId } = state!
  const dispatch = useShoppingDispatch()

  const [openDetail, setOpenDetail] = useState(false)

  const [selected, setSelect] = useState<EnumSaleMode>(0)

  const [isPending, startTransition] = useTransition()
  const onSelectOrderType = (type: EnumSaleMode) => {
    if (isPending) { return }
    setSelect(type)
    dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: type })
    // 重置预估金额
    dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
    dispatch({ type: ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION_STATUS, data: false })
  }

  const handleClickLayout = () => {
    if (currentCheckedPurchaserId === itemData?.purchaser_id) {
      return
    }
    dispatch({ type: ShoppingDispatchType.UPDATE_SELECTED_AMOUNT, data: 0 })
    dispatch({ type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE, data: selected })
    dispatch({
      type: ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID,
      data: itemData?.purchaser_id as number,
    })
    dispatch({ type: ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION_STATUS, data: false })
  }
  const handleOpenDetail = () => {
    setOpenDetail(isOpen => !isOpen)
    handleClickLayout()
  }
  // 统计已选面料
  const materialChecked = useMemo(() => {
    if (!multipleSelection || isEmptyObject(multipleSelection)) { return 0 }
    return new Set(
      Object.values(multipleSelection)?.reduce((prev, item: Goods) => {
        if (item.sale_mode === selected) {
          return [...prev, item.product_code]
        }
        return prev
      }, []),
    ).size
  }, [multipleSelection, currentCheckedPurchaserId, selected, itemData])

  // 统计已选颜色
  const colorChecked = useMemo(() => {
    console.log('colorChecked item', multipleSelection)
    if (!multipleSelection || isEmptyObject(multipleSelection)) { return 0 }
    return new Set(
      Object.values(multipleSelection).reduce((prev, item: Goods) => {
        if (item.sale_mode === selected) {
          return [...prev, item.product_color_code]
        }
        return prev
      }, []),
    ).size
  }, [multipleSelection, currentCheckedPurchaserId, selected, itemData])

  // 统计已选条数 / 米数
  const lengthOrRollChecked = useMemo(() => {
    console.log('lengthOrRollChecked item', multipleSelection)
    if (!multipleSelection || isEmptyObject(multipleSelection)) { return 0 }
    return (
      Object.values(multipleSelection).reduce((prev, item: Goods) => {
        return prev + item.count
      }, 0) || 0
    )
  }, [multipleSelection, currentCheckedPurchaserId, selected, itemData])

  const { fetchData } = ShoppingCartListApi()
  // 更新当前客户的多选项
  const updatePurchaserMultipleSelection = (purchaserId, payload, operationType: OperationType, goodsId: number) => {
    if (operationType === 'add') {
      dispatch({
        type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
        data: {
          purchaserId,
          multipleSelection: produce(multipleSelection, (multipleSelectionDraft) => {
            if (!multipleSelectionDraft) {
              return {
                [goodsId]: payload,
              }
            }
            else {
              multipleSelectionDraft[goodsId] = payload
            }
          }),
        },
      })
    }
    else if (operationType === 'delete') {
      const temp = { ...multipleSelection }
      delete temp?.[goodsId]
      dispatch({
        type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
        data: {
          purchaserId,
          multipleSelection: temp,
        },
      })
    }
  }
  // 发布订阅
  useEffect(() => {
    events.on('updatePurchaserMultipleSelection', updatePurchaserMultipleSelection)
    return () => {
      events.off('updatePurchaserMultipleSelection', updatePurchaserMultipleSelection)
    }
  }, [updatePurchaserMultipleSelection])
  // 发布订阅
  useEffect(() => {
    console.log('update multipleSelection', multipleSelection)
    const unsubscribe = state?.Observer?.subscribe(async(id) => {
      if (itemData?.purchaser_id !== id) { return }
      console.log('request new data start run')
      const res = await fetchData({
        purchaser_id: id,
      })
      console.log('res===>', res)
      if (res.success) {
        // 转成 对象形式
        // 4562: {
        //  id: 4562,
        //    ...
        // }
        if (!res.data.list.length) { return alert.error('修改数量失败') }
        const newGoodsKind = Object.fromEntries(
          res.data.list[0]?.[BackEndSaleModeListFieldMap[selected]].map(item => [
            item?.id,
            {
              id: item?.id,
              estimate_amount: item.estimate_amount,
              product_code: item.product_code,
              product_color_code: item.product_color_code,
              sale_mode: item.sale_mode,
              count: selected === EnumSaleMode.Bulk ? item.roll : Number(formatMeterDiv(item.length)),
            },
          ]),
        )
        dispatch({
          type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
          data: {
            purchaserId: id,
            goodsKind: newGoodsKind,
            multipleSelection: Object.fromEntries(
              Object.keys(multipleSelection!)
                .map(id => [
                  id,
                  {
                    id,
                    estimate_amount: newGoodsKind[id].estimate_amount,
                    product_code: newGoodsKind[id].product_code,
                    product_color_code: newGoodsKind[id].product_color_code,
                    sale_mode: newGoodsKind[id].sale_mode,
                    count: newGoodsKind[id].count,
                  },
                ]),
            ),
          },
        })
        setItemData(() => res.data.list[0])
      }
      else {
        alert.error('请求失败')
      }
    })
    // 取消订阅
    return unsubscribe
  }, [multipleSelection])

  return (
    <LayoutBlock
      circle
      customClassName={classnames(styles.layout, itemData?.purchaser_id === currentCheckedPurchaserId ? styles.selected : '')}
      onClick={handleClickLayout}
    >
      <View className={classNames(styles.checkbox, 'flex-row', 'justify-between')} onClick={handleOpenDetail}>
        <View className={styles.topItem}>
          <View className="flex-row items-center">
            <View className={styles.topTitle}>{itemData?.purchaser_name}</View>
            <Tag type="info" size="normal" circle customStyle={{ backgroundColor: '#f0f0f0', borderColor: 'transparent' }} plain>
              {itemData?.sale_user_name}
            </Tag>
          </View>
          <View className={styles.summary}>
            <Text>
              已选 {materialChecked} 种面料，{colorChecked} 个颜色，共{' '}
              {selected === EnumSaleMode.Bulk ? `${lengthOrRollChecked} 条` : `${(lengthOrRollChecked).toLocaleString()} 米`}
            </Text>
          </View>
        </View>
        <DrawerButtonWithMemo isOpen={openDetail} />
      </View>
      {/* 减少节点渲染 */}
      {openDetail && (
        <>
          <View className={classnames(styles.detailBox, openDetail ? styles.drawerOpen : styles.drawerClose)}>
            <View className={styles.checkbox}>
              <Divider customClassName={styles.line}></Divider>
            </View>
            <View className={styles.orderType}>
              <View className={styles.orderTitle}>订单类型</View>
              <View className={styles.orderTypeDetail}>
                <SaleModeButton
                  customStyle={{ padding: '0 50rpx' }}
                  isActive={selected === EnumSaleMode.Bulk}
                  onClick={() => onSelectOrderType(EnumSaleMode.Bulk)}
                >
                  大货
                </SaleModeButton>
                <SaleModeButton
                  customStyle={{ padding: '0 50rpx' }}
                  isActive={selected === EnumSaleMode.Plate}
                  onClick={() => onSelectOrderType(EnumSaleMode.Plate)}
                >
                  剪板
                </SaleModeButton>
                <SaleModeButton
                  customStyle={{ padding: '0 50rpx' }}
                  isActive={selected === EnumSaleMode.BulkCut}
                  onClick={() => onSelectOrderType(EnumSaleMode.BulkCut)}
                >
                  散剪
                </SaleModeButton>
              </View>
            </View>
            <View className={styles.orderColor}>
              <Divider customClassName={styles.line}></Divider>
              <View className={classnames(styles.orderTitle, 'justify-between')}>
                <Text>布料颜色</Text>
                <Tag type="danger" size="normal" circle plain>
                  {selectList[selected].title}单位：{selectList[selected].unit}
                </Tag>
              </View>
            </View>
            <View className={styles.orderContainer}>
              <GoodsListWithMemo
                multipleSelection={multipleSelection}
                itemData={itemData}
                selected={selected}
                isPending={isPending}
                startTransition={startTransition}
              />
            </View>
          </View>
        </>
      )}
    </LayoutBlock>
  )
}

// State 分割组件 思路就是把 context 直接通过 props 的形式传给组件，这样的话就解决了 context 强制刷新 memo 的问题了
// 那么当 context 内的 value 被更新的时候，react 只会强制渲染 Wrapper
const withStateSlice = (comp, slice) => {
  const MemoComp = memo(comp, (prevProps, nextProps) => {
    let needMemo = true
    if (JSON.stringify(prevProps.itemData) !== JSON.stringify(nextProps.itemData)) {
      needMemo = false
    }
    if (prevProps.itemData.purchaser_name === 'JENNIE') {
      console.log('------withStateSlice props-------')
      console.log('withStateSlice props prevProps', prevProps)
      console.log('withStateSlice props prevProps comparison itemData', prevProps.itemData === nextProps.itemData)
      console.log('withStateSlice props nextProps', nextProps)
      console.log('withStateSlice props prevProps comparison multipleSelection', prevProps.state.multipleSelection === nextProps.state.multipleSelection)
      console.log('withStateSlice props prevProps comparison currentCheckedPurchaserId', prevProps.state.currentCheckedPurchaserId === nextProps.state.currentCheckedPurchaserId)
      console.log('withStateSlice props prevProps comparison Observer', prevProps.state.Observer === nextProps.state.Observer)
      console.log('withStateSlice props prevProps comparison state', prevProps.state === nextProps.state)
      console.log('------withStateSlice props-------')
    }
    if (prevProps.state.Observer !== nextProps.state.Observer) {
      console.log('Observer 有变化')
      needMemo = false
    }
    if (prevProps.state.multipleSelection !== nextProps.state.multipleSelection) {
      console.log('multipleSelection 有变化')
      needMemo = false
    }
    if (prevProps.state.currentCheckedPurchaserId !== nextProps.state.currentCheckedPurchaserId) {
      console.log('currentCheckedPurchaserId 有变化')
      needMemo = false
    }
    return needMemo
  })
  const Wrapper = (props, ref) => {
    const state = useShoppingState()
    return <MemoComp ref={ref} state={slice(state, props)} {...props} />
  }
  return memo(forwardRef(Wrapper))
}

const ShoppingCartItemWithStateSlice = withStateSlice(ShoppingCartItem, (state: ShoppingStateContextValue, props) => ({
  multipleSelection: state.colorStore?.[props.itemData?.purchaser_id]?.multipleSelection,
  currentCheckedPurchaserId: state.currentCheckedPurchaserId,
  Observer: state.Observer,
}))

export default ShoppingCartItemWithStateSlice
