import React, { FC, useEffect, useState } from 'react'
import {
  __experimentalHeading as Heading,
  Button,
  ButtonGroup,
  Notice,
  Snackbar,
  Spinner,
} from '@wordpress/components'
import bringLogo from '../../assets/img/Bring_logo.svg'
import './styles.scss'
import {
  BookingRequest,
  MybringCustomerAndServices,
  Order,
  Parcel,
  ServiceDetails,
} from './model/models'
import apiFetch from '@wordpress/api-fetch'
import CustomerSelector from './components/CustomerSelector'
import ShippingOptionSelector from './components/ShippingOptionSelector'
import PackageDetails from './components/PackageDetails'
import { redo, pages, search, undo } from '@wordpress/icons'
import { useI18n } from '@wordpress/react-i18n'
import FeedbackForm from './components/FeedbackForm'
// @ts-expect-error 7016
import { getAdminLink } from '@woocommerce/settings'
import CustomsInformation from './CustomsInformation'
import { useEnableWpCompatOverlaySlot } from '@wordpress/ui'

const OrderDetails: FC = () => {
  const { __ } = useI18n()
  useEnableWpCompatOverlaySlot()
  const [selectedShippingOption, setSelectedShippingOption] = useState<string>()
  const [order, setOrder] = useState<Order>()
  const [numberOfItemsMissingHsCode, setNumberOfItemsMissingHsCode] =
    useState<number>(0)
  const [loading, setLoading] = useState<boolean>(false)
  const [selectedCustomer, setSelectedCustomer] = useState<string>()
  const [inProgress, setInProgress] = useState<boolean>(false)
  const [parcels, setParcels] = useState<Array<Parcel>>([])
  const [labelsInProgress, setLabelsInProgress] = useState(false)
  const [waybillsInProgress, setWaybillsInProgress] = useState(false)
  const [returnLabelsInProgress, setReturnLabelsInProgress] = useState(false)
  const [labelFailure, setLabelFailure] = useState(false)
  const [waybillFailure, setWaybillFailure] = useState(false)
  const [bringNotSelected, setBringNotSelected] = useState(false)
  const [updateAvailable, setUpdateAvailable] = useState<boolean>(false)
  const [availableServices, setAvailableServices] = useState<
    Array<ServiceDetails>
  >([])
  const [error, setError] = useState<boolean>(false)
  const [bookingError, setBookingError] = useState<boolean>(false)
  const [customersAndServices, setCustomersAndServices] = useState<
    Array<MybringCustomerAndServices>
  >([])
  const [validationFailed, setValidationFailed] = useState<boolean>(false)

  const urlParams = new URLSearchParams(window.location.search)
  const orderId = urlParams.get('post') || urlParams.get('id')

  const fetchOrder = (id: string) => {
    return apiFetch<Order>({
      path: `/posten-bring-checkout/orders/${id}`,
    }).then((response: Order) => {
      if (response) {
        setOrder(response)
        setNumberOfItemsMissingHsCode(
          (response.nvit &&
            response.items.filter(item => !item.hs_code || item.hs_code === '')
              .length) ||
            0
        )
        setBringNotSelected(
          (!response.order_shipping_option ||
            response.order_shipping_option === '') &&
            response.mybring_bookings?.length === 0
        )
        setValidationFailed(
          response.order_validation_errors.length > 0 &&
            response.order_validation_errors.filter(it => it.bookingDisabled)
              .length === response.order_validation_errors.length
        )
      }
      return response
    })
  }

  const fetchCustomers = (from: string, to: string) => {
    return apiFetch<Array<MybringCustomerAndServices>>({
      path: `/posten-bring-checkout/customers?from=${from}&to=${to}`,
    }).then(response => {
      if (response) {
        setCustomersAndServices(response)
        if (response.length > 0) {
          const defaultCustomer = response.find(it => it.defaultCustomer)
          setSelectedCustomer(
            defaultCustomer?.customerNumber || response[0].customerNumber
          )
        }
      }
    })
  }

  const getAvailableServices = (
    from: string,
    to: string,
    totalWeight?: number
  ) => {
    return apiFetch<Array<ServiceDetails>>({
      path: `/posten-bring-checkout/services?from=${from}&to=${to}&weight=${
        totalWeight || 0 / 1000
      }`,
    }).then(response => {
      if (response) {
        setAvailableServices(response)
      }
    })
  }

  useEffect(() => {
    // @ts-expect-error 2339
    if (window.prefetchedOrder && window.prefetchedOrder[orderId]) {
      // @ts-expect-error 2339
      setUpdateAvailable(window.prefetchedOrder?.updateAvailable)
      // @ts-expect-error 2339
      const prefetchedData = window.prefetchedOrder[orderId]
      const prefetchedOrder = prefetchedData.order as Order

      setOrder(prefetchedOrder)
      setNumberOfItemsMissingHsCode(
        (prefetchedOrder.nvit &&
          prefetchedOrder.items.filter(
            item => !item.hs_code || item.hs_code === ''
          ).length) ||
          0
      )
      setBringNotSelected(
        (!prefetchedOrder.order_shipping_option ||
          prefetchedOrder.order_shipping_option === '') &&
          prefetchedOrder.mybring_bookings?.length === 0
      )
      setValidationFailed(
        prefetchedOrder.order_validation_errors.length > 0 &&
          prefetchedOrder.order_validation_errors.filter(
            it => it.bookingDisabled
          ).length === prefetchedOrder.order_validation_errors.length
      )
      setCustomersAndServices(
        prefetchedData.customers as Array<MybringCustomerAndServices>
      )
      if (prefetchedData.customers.length > 0) {
        const defaultCustomer = (
          prefetchedData.customers as Array<MybringCustomerAndServices>
        ).find(it => it.defaultCustomer)
        setSelectedCustomer(
          defaultCustomer?.customerNumber ||
            prefetchedData.customers[0].customerNumber
        )
      }

      setAvailableServices(
        prefetchedData.shippingOptions as Array<ServiceDetails>
      )
    } else {
      const fetchOrderCustomersAndServices = async (id: string) => {
        await fetchOrder(id)
          .then(orderResult => {
            return Promise.all([
              fetchCustomers(orderResult.from_country, orderResult.to_country),
              getAvailableServices(
                orderResult.from_country,
                orderResult.to_country,
                orderResult.total_weight
              ),
            ])
          })
          .then(() => setLoading(false))
          .catch(() => {
            setLoading(false)
            setError(true)
          })
      }

      if (orderId) {
        setError(false)
        setLoading(true)
        fetchOrderCustomersAndServices(orderId)
      }
    }
  }, [orderId])

  useEffect(() => {
    if (
      selectedCustomer &&
      selectedShippingOption === undefined &&
      order?.order_shipping_option
    ) {
      setSelectedShippingOption(order.order_shipping_option)
    }
  }, [selectedShippingOption, selectedCustomer, order?.order_shipping_option])

  function getServiceCode(bookingServiceCode: string): string {
    switch (bookingServiceCode) {
      case 'PICKUP_PARCEL':
        return '0340'
      case 'PICKUP_PARCEL_BULK':
        return '0342'
      case 'HOME_DELIVERY_PARCEL':
        return '0349'
      default:
        return bookingServiceCode
    }
  }

  const placeOrder = async () => {
    setInProgress(true)
    setBookingError(false)

    const data = {
      orderRef: orderId,
      testIndicator: false,
      selectedShippingOption,
      customerNumber: selectedCustomer,
      packages: parcels.map(parcel => ({
        weightInKg: parcel.weightInGrams / 1000,
      })),
    } as BookingRequest

    apiFetch({
      path: `/posten-bring-checkout/bookings?orderId=${order?.order_id}`,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      data,
    })
      .then(() => {
        setInProgress(false)
        setLoading(true)

        return fetchOrder(order!.order_id)
      })
      .then(updatedOrder => {
        setOrder(updatedOrder)
        setLoading(false)
      })
      .catch(() => {
        setLoading(false)
        setInProgress(false)
        setBookingError(true)
      })
  }

  const getLabels = async (labelType: string) => {
    setLabelFailure(false)
    const newTab = window.open('', '_blank')
    const response = await apiFetch<Response, false>({
      path: `/posten-bring-checkout/labels?orderIds=${orderId}&labelType=${labelType}`,
      method: 'GET',
      headers: {
        Accept: 'application/pdf',
      },
      parse: false,
    }).catch(_ => {
      setLabelFailure(true)
    })
    setLabelsInProgress(false)
    setReturnLabelsInProgress(false)
    if (response?.ok) {
      const blob = await response.blob()
      const url = window.URL.createObjectURL(
        new Blob([blob], { type: 'application/pdf' })
      )

      if (newTab) {
        newTab.location.href = url
      }
    }
  }

  const getWaybills = async () => {
    setWaybillFailure(false)
    const newTab = window.open('', '_blank')
    const response = await apiFetch<Response, false>({
      path: `/posten-bring-checkout/waybills?orderIds=${orderId}`,
      method: 'GET',
      headers: {
        Accept: 'application/pdf',
      },
      parse: false,
    }).catch(_ => {
      setWaybillFailure(true)
    })
    setWaybillsInProgress(false)

    if (response?.ok) {
      const blob = await response.blob()
      const url = window.URL.createObjectURL(
        new Blob([blob], { type: 'application/pdf' })
      )

      if (newTab) {
        newTab.location.href = url
      }
    }
  }

  return (
    <>
      <div className="container mll mtl mrl mbm">
        {loading ? (
          <div className="flex flex-dir-row justify-cc mtm mbl">
            <Spinner
              style={{
                height: '40px',
                width: '40px',
              }}
            />
          </div>
        ) : (
          <>
            {bringNotSelected ? (
              <div>
                <div className="flex justify-csb">
                  <Heading level={3} weight={200}>
                    {__(
                      'Bring has not been selected for this order',
                      'posten-bring-checkout'
                    )}
                  </Heading>
                  <img src={bringLogo} alt="" className="logo" />
                </div>
                <div className="mbm">
                  <Button
                    variant="secondary"
                    __next40pxDefaultSize={true}
                    onClick={() => {
                      setBringNotSelected(false)
                    }}
                  >
                    {__('Ship with Bring', 'posten-bring-checkout')}
                  </Button>
                </div>
              </div>
            ) : (
              <>
                {order && (order.mybring_bookings?.length || 0) > 0 && (
                  <div>
                    <div className="flex justify-csb">
                      <Heading level={3} weight={200}>
                        {__(
                          'Shipment has been ordered',
                          'posten-bring-checkout'
                        )}
                      </Heading>
                      <img src={bringLogo} alt="" className="logo" />
                    </div>
                    <div>
                      <div className="mbm">
                        <ButtonGroup className="mtm">
                          <Button
                            variant="primary"
                            __next40pxDefaultSize={true}
                            icon={redo}
                            className="mrs"
                            isBusy={labelsInProgress}
                            onClick={() => {
                              setLabelsInProgress(true)
                              getLabels('LABEL')
                            }}
                          >
                            {__('Print label', 'posten-bring-checkout')}
                          </Button>
                          {order.mybring_bookings[0].waybillUrl && (
                            <Button
                              variant="secondary"
                              __next40pxDefaultSize={true}
                              icon={pages}
                              className="mrs"
                              isBusy={waybillsInProgress}
                              onClick={() => {
                                setWaybillsInProgress(true)
                                getWaybills()
                              }}
                            >
                              {__('Print waybill', 'posten-bring-checkout')}
                            </Button>
                          )}
                          {order.mybring_bookings[0].returnLabelUrl && (
                            <Button
                              variant="secondary"
                              __next40pxDefaultSize={true}
                              icon={undo}
                              className="mrs"
                              isBusy={returnLabelsInProgress}
                              onClick={() => {
                                setReturnLabelsInProgress(true)
                                getLabels('RETURN')
                              }}
                            >
                              {__(
                                'Print return label',
                                'posten-bring-checkout'
                              )}
                            </Button>
                          )}
                          <a
                            href={order.mybring_bookings[0].trackingUrl}
                            target="_blank"
                            rel="noreferrer"
                          >
                            <Button
                              variant="secondary"
                              icon={search}
                              __next40pxDefaultSize={true}
                            >
                              {__('Tracking', 'posten-bring-checkout')}
                            </Button>
                          </a>
                        </ButtonGroup>
                        {labelFailure && (
                          <Snackbar
                            className="mtm"
                            explicitDismiss
                            politeness="assertive"
                            onRemove={() => setLabelFailure(false)}
                          >
                            {__(
                              'An error occurred while generating label. Please try again',
                              'posten-bring-checkout'
                            )}
                          </Snackbar>
                        )}
                        {waybillFailure && (
                          <Snackbar
                            className="mtm"
                            explicitDismiss
                            politeness="assertive"
                            onRemove={() => setWaybillFailure(false)}
                          >
                            {__(
                              'An error occurred while generating waybill. Please try again',
                              'posten-bring-checkout'
                            )}
                          </Snackbar>
                        )}
                        <div className="mtl">
                          <Heading level={4} weight={400}>
                            {__('Shipment ', 'posten-bring-checkout') +
                              order.mybring_bookings[0].consignmentNumber}
                          </Heading>
                          <div>
                            {
                              availableServices?.find(
                                service =>
                                  service.service_id ===
                                  getServiceCode(
                                    order.mybring_bookings[0].serviceId
                                  )
                              )?.name
                            }
                          </div>
                          {order.mybring_bookings[0].waybillUrl && (
                            <div className="mtm">
                              <span>
                                {__(
                                  'Do you want to order ',
                                  'posten-bring-checkout'
                                )}{' '}
                                <a
                                  href="https://www.mybring.com/order-pickup/"
                                  target="_blank"
                                  rel="noreferrer"
                                >
                                  {__('pickup', 'posten-bring-checkout')}
                                </a>
                                ?
                              </span>
                            </div>
                          )}
                        </div>
                        {order.from_country !== order.to_country &&
                          !(
                            order.mybring_bookings[0].serviceId === '0340' &&
                            order.from_country === 'NO'
                          ) && (
                            <div className="mtm flex flex-dir-col">
                              <span>
                                {__('Download ', 'posten-bring-checkout')}
                                <a
                                  href="https://www.bring.no/tjenester/toll/handelsfaktura.pdf"
                                  target="_blank"
                                  rel="noreferrer"
                                >
                                  {__(
                                    'commercial invoice',
                                    'posten-bring-checkout'
                                  )}
                                </a>
                              </span>
                              <span>
                                {__('Download ', 'posten-bring-checkout')}
                                <a
                                  href="https://www.bring.no/tjenester/toll/Proformafaktura.pdf"
                                  target="_blank"
                                  rel="noreferrer"
                                >
                                  {__(
                                    'Proforma invoice',
                                    'posten-bring-checkout'
                                  )}
                                </a>
                              </span>
                            </div>
                          )}
                      </div>
                    </div>
                  </div>
                )}
                {order && !error && order.mybring_bookings?.length === 0 && (
                  <div>
                    <div className="flex justify-csb">
                      <Heading level={3} weight={200}>
                        {__('Book shipping', 'posten-bring-checkout')}
                      </Heading>
                      <img src={bringLogo} alt="" className="logo" />
                    </div>
                    <div>
                      <div className="flex flex-dir-row justify-cfs mbm">
                        <div className="w100p">
                          <CustomerSelector
                            label={__(
                              'Customer number',
                              'posten-bring-checkout'
                            )}
                            customers={customersAndServices}
                            selectedCustomer={selectedCustomer}
                            onSelect={setSelectedCustomer}
                            className="mbm"
                          />
                          <ShippingOptionSelector
                            label={__(
                              'Shipping options',
                              'posten-bring-checkout'
                            )}
                            selectedShippingOption={selectedShippingOption}
                            setSelectedShippingOption={
                              setSelectedShippingOption
                            }
                            availableServices={availableServices}
                            selectedCustomer={selectedCustomer}
                            customersAndServices={customersAndServices}
                            preSelectedShippingOption={
                              order.order_shipping_option
                            }
                          />
                          <PackageDetails
                            selectedShippingOption={selectedShippingOption}
                            availableServices={availableServices}
                            items={order.items}
                            toCountry={order.to_country}
                            totalWeightInGrams={order.total_weight}
                            parcels={parcels}
                            setParcels={setParcels}
                          />
                          {bookingError && (
                            <Notice
                              status="error"
                              isDismissible={false}
                              className="mtl"
                            >
                              {__(
                                'An error occurred! We have been notified and are investigating. Please try again later, or contact us via ',
                                'posten-bring-checkout'
                              )}
                              <a
                                href={`mailto:${__(
                                  'checkout.implementering@posten.no',
                                  'posten-bring-checkout'
                                )}`}
                              >
                                {__(
                                  'checkout.implementering@posten.no',
                                  'posten-bring-checkout'
                                )}
                              </a>
                            </Notice>
                          )}
                          {order.nvit && numberOfItemsMissingHsCode > 0 && (
                            <CustomsInformation
                              items={order.items}
                              onChange={() => {
                                setLoading(true)
                                fetchOrder(order!.order_id)
                                  .then(updatedOrder => {
                                    setOrder(updatedOrder)
                                    setNumberOfItemsMissingHsCode(
                                      (updatedOrder.nvit &&
                                        updatedOrder.items.filter(
                                          item =>
                                            !item.hs_code || item.hs_code === ''
                                        ).length) ||
                                        0
                                    )
                                    setLoading(false)
                                  })
                                  .finally(() => {
                                    setLoading(false)
                                  })
                              }}
                            />
                          )}
                          {order.order_validation_errors.length > 0 && (
                            <Notice
                              status="warning"
                              isDismissible={false}
                              className="mtl"
                            >
                              {order.order_validation_errors.map(
                                (validationError, idx) => (
                                  <div key={idx}>{validationError.message}</div>
                                )
                              )}
                            </Notice>
                          )}
                          <p className="mtl terms">
                            {__(
                              'By ordering, you accept our ',
                              'posten-bring-checkout'
                            )}
                            <a
                              href="https://www.bring.com/services/prices-and-conditions"
                              target="_blank"
                              rel="noreferrer"
                            >
                              {__(
                                'terms and conditions.',
                                'posten-bring-checkout'
                              )}
                            </a>
                          </p>
                          <Button
                            variant={'primary'}
                            className={'mtxs'}
                            onClick={placeOrder}
                            __next40pxDefaultSize={true}
                            isBusy={inProgress}
                            disabled={
                              !selectedShippingOption ||
                              !selectedCustomer ||
                              validationFailed
                            }
                          >
                            {__('Book shipping', 'posten-bring-checkout')}
                          </Button>
                        </div>
                      </div>
                    </div>
                  </div>
                )}
              </>
            )}
          </>
        )}
      </div>
      {bringNotSelected ? null : (
        <div className="flex flex-dir-row align-ic mll mbm gal flex-wrap">
          <FeedbackForm />
          {updateAvailable && (
            <span className="update-available">
              {__(
                'New version of Posten Bring Checkout available! ',
                'posten-bring-checkout'
              )}
              <a href={getAdminLink('plugins.php')}>
                {__('Update now.', 'posten-bring-checkout')}
              </a>
            </span>
          )}
        </div>
      )}
    </>
  )
}

export default OrderDetails
