import React, { FC, useEffect, useState } from 'react'
import postenLogo from '../../../assets/img/Posten_logo.svg'
import bringLogo from '../../../assets/img/Bring_logo.svg'
import root from 'react-shadow'
import {
  EnvironmentalData,
  LeadTime,
  MetaData,
  PickupPoint as PickupPointData,
  PostenBringShippingOptions,
} from './model/models'
import GeneralShippingOption from './blocks/GeneralShippingOption'
import HomeDelivery from './blocks/HomeDelivery'
import PickupPoints from './blocks/PickupPoints'
import styles from './style.scss'
import { __ } from '@wordpress/i18n'

export declare interface PostenBringCheckoutBlockProps {
  cart: Cart
  checkoutExtensionData: CheckoutExtensionData
  darkMode?: boolean
}

export interface CheckoutExtensionData {
  setExtensionData: (namespace: string, id: string, data: any) => void
}

export interface Cart {
  shippingRates: Array<WooShippingRate>
  shippingAddress: ShippingAddress
  billingAddress: ShippingAddress
}

interface ShippingAddress {
  phone?: string
  country: string
  first_name?: string
  last_name?: string
  address_1?: string
  address_2?: string
}

interface ShippingRate {
  rate_id: string
  selected: boolean
  meta_data: Array<MetaData>
}

interface WooShippingRate {
  shipping_rates: Array<ShippingRate>
}

const PostenBringCheckoutBlock: FC<PostenBringCheckoutBlockProps> = ({
  checkoutExtensionData,
  darkMode,
  cart,
  ...rest
}) => {
  const { setExtensionData } = checkoutExtensionData
  const [selectedPickupPoint, setSelectedPickupPoint] = useState<string>()
  const [selectedDeliveryDate, setSelectedDeliveryDate] = useState<string>()

  const selectedShippingRate = cart?.shippingRates[0]?.shipping_rates?.find(
    (it: ShippingRate) => it.selected
  ) as ShippingRate | undefined
  const selectedShippingOption = selectedShippingRate?.rate_id
  const metaData: Array<MetaData> = selectedShippingRate?.meta_data || []

  const brand = metaData.find(it => it.key === 'brand')?.value as string
  const serviceName = metaData.find(it => it.key === 'service_name')
    ?.value as string
  const environmentalData = metaData.find(it => it.key === 'environmental_data')
    ?.value as EnvironmentalData | undefined
  const serviceDescription = metaData.find(
    it => it.key === 'service_description'
  )?.value as string
  const leadTime = metaData.find(it => it.key === 'lead_time')
    ?.value as LeadTime
  const pickupPoints = metaData.find(it => it.key === 'pickup_points')
    ?.value as Array<PickupPointData> | [] as PickupPointData[]

  // @ts-expect-error 2339
  const { VALIDATION_STORE_KEY, CART_STORE_KEY } = window.wc.wcBlocksData
  // @ts-expect-error 2304
  const { dispatch, select } = wp.data
  const { setValidationErrors, clearValidationError } =
    dispatch(VALIDATION_STORE_KEY)
  const { setCartData } = dispatch(CART_STORE_KEY)
  const { getValidationError } = select(VALIDATION_STORE_KEY)
  const phoneValidationError = getValidationError('shipping_phone')
  const firstNameValidationError = getValidationError('shipping_first_name')
  const lastNameValidationError = getValidationError('shipping_last_name')

  useEffect(() => {
    const recipientCountry = cart?.shippingAddress?.country

    if (
      ['NO', 'DK'].includes(recipientCountry) &&
      (!cart.shippingAddress?.phone ||
        ['+47', '+45'].includes(cart.shippingAddress?.phone))
    ) {
      const shippingAddress = Object.assign({}, cart.shippingAddress, {
        phone: recipientCountry === 'NO' ? '+47' : '+45',
      })

      setCartData(Object.assign({}, cart, { shippingAddress }))
    } else if (
      !['NO', 'DK'].includes(recipientCountry) &&
      cart.shippingAddress?.phone &&
      ['+47', '+45'].includes(cart.shippingAddress?.phone)
    ) {
      const shippingAddress = Object.assign({}, cart.shippingAddress, {
        phone: '',
      })

      setCartData(Object.assign({}, cart, { shippingAddress }))
    }
  }, [cart?.shippingAddress?.country])

  useEffect(() => {
    if (
      selectedShippingOption &&
      [
        PostenBringShippingOptions.PARCEL_LOCKER,
        PostenBringShippingOptions.PIKCUP_POINT,
        PostenBringShippingOptions.HOME_DELIVERY,
        PostenBringShippingOptions.MAILBOX,
        PostenBringShippingOptions.GROUPAGE,
        PostenBringShippingOptions.PALLET,
        PostenBringShippingOptions.PARCEL_TO_BUSINESS,
        // @ts-expect-error 2345
      ].includes(selectedShippingOption)
    ) {
      const phoneNumber = cart?.shippingAddress?.phone?.replace(
        new RegExp('[^\\d+]|(?<=\\+)\\D'),
        ''
      )
      const recipientCountry = cart?.shippingAddress?.country
      let validationError: string | null = null

      if (
        phoneNumber &&
        !new RegExp('^((\\+|(00))(45|46|47|358))').test(phoneNumber)
      ) {
        if (recipientCountry === 'SE') {
          if (!new RegExp('^(((\\+|(00))46)?(0?7)\\d{8})$').test(phoneNumber)) {
            if (
              phoneNumber.length === 8 &&
              !new RegExp('^((\\+|(00))46)?(0?7)').test(phoneNumber) &&
              !new RegExp('^((\\+|(00))(45|47|358))').test(phoneNumber)
            ) {
              validationError = __(
                'Please provide a phone number including country code prefix',
                'posten-bring-checkout'
              )
            }
          } else if (phoneNumber.length < 11) {
            validationError = __(
              'Phone number is required',
              'posten-bring-checkout'
            )
          }
        } else if (recipientCountry === 'FI') {
          if (
            !new RegExp('^(((\\+|(00))358)?(0457|04\\d|050)\\d{7})$').test(
              phoneNumber
            )
          ) {
            if (
              (phoneNumber.length === 10 || phoneNumber.length === 11) &&
              !new RegExp('^((\\+|(00))46)?(0?7)').test(phoneNumber) &&
              !new RegExp('^((\\+|(00))(45|47|358))').test(phoneNumber)
            ) {
              validationError = __(
                'Please provide a phone number including country code prefix',
                'posten-bring-checkout'
              )
            } else if (phoneNumber.length < 11) {
              validationError = __(
                'Phone number is required',
                'posten-bring-checkout'
              )
            }
          }
        } else if (['NO', 'DK', 'SJ'].includes(recipientCountry)) {
          if (!new RegExp('^((\\+|(00))(45|46|47|358))').test(phoneNumber)) {
            validationError = __(
              'Please provide a phone number including country code prefix',
              'posten-bring-checkout'
            )
          } else if (phoneNumber.length < 11) {
            validationError = __(
              'Phone number is required',
              'posten-bring-checkout'
            )
          }
        }
      } else if (
        ['NO', 'DK', 'SE', 'SJ', 'FI'].includes(recipientCountry) &&
        (!phoneNumber || phoneNumber.length < 11)
      ) {
        validationError = __(
          'Phone number is required',
          'posten-bring-checkout'
        )
      }

      if (validationError) {
        setValidationErrors({
          shipping_phone: {
            message: validationError,
            hidden: false,
          },
        })
      } else {
        clearValidationError('shipping_phone')
      }
    }
  }, [
    cart?.shippingAddress?.phone,
    cart?.shippingAddress?.country,
    clearValidationError,
    setValidationErrors,
    phoneValidationError,
    selectedShippingOption,
  ])

  useEffect(() => {
    if (
      selectedShippingOption &&
      [
        PostenBringShippingOptions.PARCEL_LOCKER,
        PostenBringShippingOptions.PIKCUP_POINT,
        PostenBringShippingOptions.HOME_DELIVERY,
        PostenBringShippingOptions.MAILBOX,
        PostenBringShippingOptions.GROUPAGE,
        PostenBringShippingOptions.PALLET,
        PostenBringShippingOptions.PARCEL_TO_BUSINESS,
        // @ts-expect-error 2345
      ].includes(selectedShippingOption)
    ) {
      const emojis = new RegExp(/\p{Emoji_Presentation}/gu)
      if (cart.shippingAddress?.first_name) {
        if (emojis.test(cart.shippingAddress.first_name)) {
          setValidationErrors({
            shipping_first_name: {
              message: __(
                "First name can't contain emojis",
                'posten-bring-checkout'
              ),
              hidden: false,
            },
          })
        } else {
          clearValidationError('shipping_first_name')
        }
      }

      if (cart.shippingAddress?.last_name) {
        if (emojis.test(cart.shippingAddress.last_name)) {
          setValidationErrors({
            shipping_last_name: {
              message: __(
                "Last name can't contain emojis",
                'posten-bring-checkout'
              ),
              hidden: false,
            },
          })
        } else {
          clearValidationError('shipping_last_name')
        }
      }

      if (cart.shippingAddress?.address_1) {
        if (emojis.test(cart.shippingAddress.address_1)) {
          setValidationErrors({
            shipping_address_1: {
              message: __(
                "Address can't contain emojis",
                'posten-bring-checkout'
              ),
              hidden: false,
            },
          })
        } else {
          clearValidationError('shipping_address_1')
        }
      }

      if (cart.shippingAddress?.address_2) {
        if (emojis.test(cart.shippingAddress.address_2)) {
          setValidationErrors({
            shipping_address_2: {
              message: __(
                "Address can't contain emojis",
                'posten-bring-checkout'
              ),
              hidden: false,
            },
          })
        } else {
          clearValidationError('shipping_address_2')
        }
      }
    }
  }, [
    clearValidationError,
    setValidationErrors,
    selectedShippingOption,
    cart?.shippingAddress?.last_name,
    cart?.shippingAddress?.first_name,
    cart?.shippingAddress?.address_1,
    cart?.shippingAddress?.address_2,
    firstNameValidationError,
    lastNameValidationError,
  ])

  useEffect(() => {
    if (
      (selectedShippingOption === PostenBringShippingOptions.PARCEL_LOCKER ||
        selectedShippingOption === PostenBringShippingOptions.PIKCUP_POINT) &&
      pickupPoints &&
      pickupPoints.length > 0 &&
      (!selectedPickupPoint ||
        !pickupPoints.find(pp => pp.id === selectedPickupPoint))
    ) {
      setSelectedPickupPoint(pickupPoints[0].id)
    } else if (
      selectedShippingOption !== PostenBringShippingOptions.PIKCUP_POINT &&
      selectedShippingOption !== PostenBringShippingOptions.PARCEL_LOCKER
    ) {
      setSelectedPickupPoint(undefined)
    }

    if (
      selectedShippingOption === PostenBringShippingOptions.HOME_DELIVERY &&
      leadTime?.deliveryDateAlternatives?.length > 0 &&
      !selectedDeliveryDate
    ) {
      setSelectedDeliveryDate(leadTime.deliveryDateAlternatives[0].deliveryDate)
    } else if (
      selectedShippingOption !== PostenBringShippingOptions.HOME_DELIVERY
    ) {
      setSelectedDeliveryDate(undefined)
    }
  }, [
    selectedShippingOption,
    pickupPoints,
    leadTime,
    selectedDeliveryDate,
    selectedPickupPoint,
  ])

  useEffect(() => {
    setExtensionData(
      'posten-bring-checkout',
      'selectedBringPickupPointId',
      selectedPickupPoint
    )
  }, [selectedPickupPoint, setExtensionData])

  useEffect(() => {
    const selectedAlternative = leadTime?.deliveryDateAlternatives?.find(
      alternative => alternative.deliveryDate === selectedDeliveryDate
    )
    if (selectedAlternative) {
      setExtensionData(
        'posten-bring-checkout',
        'selectedBringDeliveryDate',
        selectedDeliveryDate
      )
      setExtensionData(
        'posten-bring-checkout',
        'selectedBringDeliveryShippingDate',
        selectedAlternative.shippingDate
      )
    }
  }, [
    selectedDeliveryDate,
    setExtensionData,
    leadTime?.deliveryDateAlternatives,
  ])

  const logo = brand === 'Bring' ? bringLogo : postenLogo

  return selectedShippingOption?.startsWith('posten-bring-checkout') &&
    brand ? (
    <root.div style={{ outline: 'none' }}>
      <div
        id="posten-bring-checkout"
        className={`${brand === 'Bring' ? 'bring' : 'posten'} ${
          darkMode ? 'dark' : ''
        }`}
      >
        <div className="card">
          <div className="flex flex-dir-row justify-csb align-ic flex-wrap mbm">
            <span className="service-name">{serviceName}</span>
            <div>
              <img className="logo" src={logo} alt="" />
            </div>
          </div>
          {[
            PostenBringShippingOptions.MAILBOX,
            PostenBringShippingOptions.GROUPAGE,
            PostenBringShippingOptions.PARCEL_TO_BUSINESS,
            PostenBringShippingOptions.PALLET,
            // @ts-expect-error 2345
          ].includes(selectedShippingOption) && (
            <GeneralShippingOption
              leadTime={leadTime}
              environmentalData={environmentalData}
              serviceDescription={serviceDescription}
            />
          )}
          {(selectedShippingOption ===
            PostenBringShippingOptions.PARCEL_LOCKER ||
            selectedShippingOption ===
              PostenBringShippingOptions.PIKCUP_POINT) && (
            <PickupPoints
              pickupPoints={pickupPoints}
              serviceDescription={serviceDescription}
              environmentalData={environmentalData}
              selectedPickupPoint={selectedPickupPoint}
              onSelect={setSelectedPickupPoint}
              displayDistance={brand === 'Bring'}
            />
          )}
          {selectedShippingOption ===
            PostenBringShippingOptions.HOME_DELIVERY && (
            <HomeDelivery
              serviceDescription={serviceDescription}
              environmentalData={environmentalData}
              selectedDeliveryDate={selectedDeliveryDate}
              leadTime={leadTime}
              onSelect={setSelectedDeliveryDate}
            />
          )}
        </div>
      </div>
      <style type="text/css">{styles}</style>
    </root.div>
  ) : null
}

export default PostenBringCheckoutBlock
