import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import {
  Environment,
  initialize,
  UserProfile,
  setPassportCloseCallback,
  registerBNPLPaymentCompleteHandler,
  getPreparedWindowToOpen,
  startServiceInstanceFlow,
  loadUserCredential,
  saveUserCredential, 
  Offer,
} from "credify-web-sdk"
import "antd/dist/antd.css"
import CredifyLogo from "../../resources/credify-group-logo-title.svg"
import FullScreenLoading from "../../components/FullSceenLoading"
import { useLocation } from "react-router-dom"
import { getMarketApiUrl, setMarketEnvironment } from "../../config"
import {
  LoginButton,
  LoginText,
  CredifyImage,
  CredifyImageWrapper,
  ServiceInstanceWrapper,
} from "./styled"
import CredifyLogo2 from "../../resources/credify.svg"
import { initOffer, mockProducts } from "./mock-bnpl-data"
import {
  ProductListStyled,
  IdWrapper,
  CurentText,
  IdInput,
  FetchInput,
  SliderWrapperStyled,
  BnplWrapper,
  BnplBackground,
  ProductContentWrapper,
  ProductContent,
  ProductBlockWrapper,
  CheckboxStyled,
} from "./BnplPage.styled"
import { BNPL_THEME_DEFAULT } from "./type"
import PaymentSucceedModal from "../../components/modals/paymentSucceed/paymentSucceedModal"
import spBackground from "../../assets/img/sp-bg-placeholder.png"
import { OfferType, OrderLine } from "../../types/common"
import {
  getDemoUser,
  lodgeNewIntent, updateUserProfile
} from "../../apis/bnpl"
import _ from "lodash"
import { formatCurrency } from "../../utils/parsers"
import InputNumberField from "../../components/input/number"
import CheckboxField from "../../components/input/checkbox"
import {
  createLodgeRequest,
  createOrderLines,
  getTotalAmount,
  getTotalQuantity,
  getUrlQueryParams,
  isSafari,
  openPopupWindow,
} from "../../utils/helpers"
import { PRODUCT_TYPE } from "credify-web-sdk"
import { getOffers } from "../../apis"
import ProductCodeSelect from "../../components/ProductCodeSelect"

const MARKET_NAME = "bnpl-consumer"

const DEFAULT_API_KEY =
  "UwbxwqQXnY66dtQm57Bt98la4AwSQodUeMyNThny4aQ7SVoN9IDrhctBCkgWdt6W"
const DEFAULT_MARKET_ID = "8319dd85-7b57-4455-a8dc-5fb1d142a400"

/**
 * This will be used for BNPL new flow
 */
function BnplPage() {
  const NONE_PRODUCT_CODE = "---none---";
  const cacheUserProfile = loadUserCredential()
  const params = getUrlQueryParams(window.location.search)
  const orderId = params?.order_id

  const [user, setUser] = useState<UserProfile>()
  const [withEkyc, setWithEkyc] = useState(true)
  const [isLoading, setLoading] = useState<boolean>(false)
  const [idText, setIdText] = useState<string>(
    orderId && cacheUserProfile?.id ? cacheUserProfile?.id : ""
  )
  const location = useLocation()
  const inputRef = useRef(null)
  const [showModal, setShowModal] = useState(false)
  const currentCart: OfferType = initOffer
  const [products, setProducts] = useState<{ [key: string]: any }>(mockProducts)
  const [offers, setOffers] = useState<Offer[]>([])
  const [productCodes, setProductCodes] = useState<
    Array<{ label?: string; value?: string }>
  >([])
  const [selectedProductCode, setSelectedProductCode] = useState("")
  const [openWithRedirect, setOpenWithRedirect] = useState(true)
  const [selectedLocale, setSelectedLocale] = useState("")
  const [useUICustomization, setUseUICustomization] = useState(false)

  const LANGUAGES: Array<{ label: string; value?: string }> = [
    {
      label: "None",
      value: "",
    },
    {
      label: "VN",
      value: "vi-VN"
    },
    {
      label: "EN",
      value: "en-US"
    },
    {
      label: "JP",
      value: "ja-JP"
    }
  ]

  const urlSearch = new URLSearchParams(location.search)
  const env = urlSearch.get("env")

  useEffect(() => {
    const apiKey = urlSearch.get("apiKey") || DEFAULT_API_KEY
    const marketId = urlSearch.get("marketId") || DEFAULT_MARKET_ID
    const useUICustomization = urlSearch.get("ui-customization") === "true";
    setUseUICustomization(useUICustomization)

    initialize(
      env as Environment,
      apiKey,
      marketId,
      useUICustomization? BNPL_THEME_DEFAULT : undefined
    )
    // Demo Market environment
    setMarketEnvironment(env as Environment)
    registerBNPLPaymentCompleteHandler(() => {
      // *** Successful Payment popup here
      setShowModal(true)
    })
    loadData()

    // Handle flow redirect
    handleEventFromRedirect()
  }, [])

  useEffect(() => {
    setPassportCloseCallback(() => {
      loadData()
    })
  }, [user])

  useEffect(() => {
    if (!productCodes || productCodes.length === 0) return

    setSelectedProductCode(productCodes[0].value!)
  }, [productCodes.length])

  const handleEventFromRedirect = async () => {
    if (!params) return
    if (orderId && cacheUserProfile?.id) {
      setShowModal(true)
      await getUserProfile()
    }
  }

  async function loadData() {
    console.log("Market Data is loading....")
    setLoading(true)
    const userProfile = await getUserProfile()
    const credifyId = userProfile?.credifyId || ""
    // TODO need to set access token when the BE requires in the future
    const result = await getOffers(MARKET_NAME, "", {
      localId: `${userProfile?.id || ""}`,
      phoneNumber: userProfile?.phoneNumber,
      countryCode: userProfile?.countryCode,
      credifyId,
    })

    if (result?.success && result.data) {
      setOffers(result.data.offers || [])
      const productCodes = result.data.offers
        .filter((offer) => offer.campaign?.product?.code)
        .map((offer) => offer?.campaign?.product?.code as string)

      if (productCodes.length > 0) {
        const productCodesViewModel = productCodes.map((code) => ({
          label: code,
          value: code,
        }))
        setProductCodes([
          {
            label: "None",
            value: NONE_PRODUCT_CODE,
          },
          ...productCodesViewModel
        ])
      }
    }

    setLoading(false)
    console.log("Market Data finish loading....")
  }

  async function getUserProfile(): Promise<UserProfile | undefined> {
    const _user = await getDemoUser(
      MARKET_NAME,
      //@ts-ignore
      inputRef?.current?.value.toString()
    )

    if (!_user) return

    const userProfile: UserProfile = {
      id: `${_user.id}`,
      firstName: _user.firstName,
      lastName: _user.lastName,
      middleName: _user.middleName,
      fullName: _user.fullName,
      phoneNumber: _user.phoneNumber,
      countryCode: _user.phoneCountryCode,
      email: _user.email,
      credifyId: _user.credifyId,
    }
    console.log({ userProfile })
    setUser(userProfile)
    setIdText(_user.id)
    saveUserCredential(JSON.stringify(userProfile))
    return userProfile
  }

  async function pushClaimCB(
    externalId: string,
    resolve: (isSuccess: boolean) => void
  ) {
    console.log("Push claim token......")
    try {
      const res = await pushClaim(user!.id!, externalId)
      console.log({ res })
      resolve(true)
    } catch (error) {
      resolve(false)
    }
  }

  async function pushClaim(localId: string, credifyId: string) {
    const body = {
      id: localId,
      credify_id: credifyId,
    }
    try {
      const pushClaimUrl = `${getMarketApiUrl()}/${MARKET_NAME}/push-claims`
      console.log({ pushClaimUrl })
      const res = await fetch(pushClaimUrl, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(body),
      })
      return res.json()
    } catch (error) {
      throw error
    }
  }

  function randomUser() {
    setIdText("")
    setTimeout(() => {
      loadData()
    }, 300)
  }

  const getIntentLink = (intentUrl: string) => {    
    if (!window.location.host.includes("localhost")) return intentUrl

    let intentRegex = /.+(?=\/dop)/g

    const intentLocalHost = intentUrl.replace(
      intentRegex,
      "http://localhost:4200"
    )

    return intentLocalHost
  }


  const handleClickBnplWithIntent = async () => {
    const locale = selectedLocale

    const selectedOffer = offers?.find((item) => item.campaign?.product?.code === selectedProductCode);
    const selectedProductType = selectedOffer?.campaign?.product?.productTypeCode;
    const currentProducts = _.clone(products)
    Object.keys(products).forEach((index) => {
      if (!currentProducts[index].selected) {
        delete currentProducts[index]
      }
    })

    const updatedCart = _.clone(currentCart)
    updatedCart.total_amount.value = totalAmount.toString()
    let order_lines: OrderLine[] = [] as OrderLine[]

    order_lines = createOrderLines(currentProducts)

    updatedCart.order_lines = order_lines
    updatedCart.reference_id = `reference_id_${+new Date()}`
    updatedCart.is_business = selectedProductType === PRODUCT_TYPE.CORPORATE_FINANCING__UNSECURED_LOAN__PO_FINANCING;

    let windowReference: Window | null = null
    const isBrowserSafari = isSafari()

    // On this async/await function, to avoid Safari open new popup issue
    // All the `async` logic should behind the getPreparedWindowToOpen() function
    if (!openWithRedirect && isBrowserSafari) {
      windowReference = getPreparedWindowToOpen()
    }

    if (updatedCart) {
      setLoading(true)
      const offerCodes = offers.map((offer) => offer.code) as string[]
      console.log("updatedCart", updatedCart)
      const user = await getUserProfile()
      updatedCart.user_id = user?.id!
      console.log("user", user)
      const result = await lodgeNewIntent(
        MARKET_NAME,
        createLodgeRequest(
          "BNPL",
          updatedCart,
          user,
          selectedProductCode === NONE_PRODUCT_CODE
            ? undefined
            : [selectedProductCode],
          offerCodes.length > 0 ? offerCodes : undefined,
          useUICustomization ? BNPL_THEME_DEFAULT : undefined
        )
      )
      console.log("result", result)
      setLoading(false)

      let appUrl = getIntentLink(result?.appUrl) as string
      if (appUrl) {
        appUrl = locale ? `${appUrl}/${locale}` : appUrl

        if (openWithRedirect) {
          window.location.href = appUrl
          return
        }

        openPopupWindow(appUrl, windowReference!)
      }
    }
  }

  const onChangeQuantity = useCallback(
    (field: string, value: number) => {
      const product = field.split("_")[0]
      const fieldChange = field.split("_")[1]
      let updatedProduct = _.clone(products)
      if (value < 0) return
      updatedProduct[product][fieldChange] = value ? Number(value) : 0
      setProducts(updatedProduct)
    },
    [products]
  )

  const onChangeProductInfo = useCallback(
    (e: any) => {
      const value = e.target.value
      const product = e.target.name.split("_")[0]
      const fieldChange = e.target.name.split("_")[1]
      let updatedProduct = _.clone(products)
      if (fieldChange === "quantity") {
        updatedProduct[product][fieldChange] = value ? Number(value) : 0
      } else if (fieldChange === "selected") {
        updatedProduct[product][fieldChange] = e.target.checked
      } else {
        updatedProduct[product][fieldChange] = value
          ? formatCurrency(value)
          : "0"
      }
      setProducts(updatedProduct)
    },
    [products]
  )

  const renderProductBlock = useMemo(() => {
    return Object.keys(products).map((item, index) => {
      return (
        <div key={`product-item-${index}`} className="product-block">
          <div className="product-row title">
            <div className="left">&nbsp;</div>
            <div className="right">{products[item].name}</div>
          </div>
          <div className="product-row content">
            <div className="left">
              <img alt="" src={products[item].img} />
            </div>
            <div className="right">
              <p className="detail">{products[item].description}</p>
              <InputNumberField
                value={products[item].price}
                onChange={(e) => onChangeProductInfo(e)}
                name={`${item}_price`}
                color="#3abb88"
                width={70}
                outline={false}
                currency="đ"
              />
            </div>
          </div>
          <div className="product-row controls">
            <CheckboxStyled>
              <CheckboxField
                name={`${item}_selected`}
                checked={products[item].selected}
                onChange={(e) => onChangeProductInfo(e)}
              />
            </CheckboxStyled>
            <div className="quantity">
              <InputNumberField
                value={products[item].quantity}
                onChange={(e) => onChangeProductInfo(e)}
                name={`${item}_quantity`}
                color="#000000"
                width={40}
                outline={true}
                hasControl
                onChangeQuantity={onChangeQuantity}
              />
            </div>
          </div>
          <div className="index-num">{index + 1}</div>
          <div className="star-block">
            <div className="star"></div>
          </div>
          <div className="btn-close">X</div>
        </div>
      )
    })
  }, [onChangeProductInfo, onChangeQuantity, products])

  const totalAmount = useMemo(() => {
    const sum = getTotalAmount(products)
    return sum
  }, [products])

  const totalQuantity = useMemo(() => {
    const sum = getTotalQuantity(products)
    return sum
  }, [products])

  const goToServiceInstance = (
    e: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    e.preventDefault()
    startServiceInstanceFlow(MARKET_NAME, user, [
      PRODUCT_TYPE.CONSUMER_FINANCING__UNSECURED_LOAN__BNPL,
    ])
  }

  const updatePhoneNumber = async () => {
    // Input country code
    let countryCode, phoneNumber
    let inputCountryCode = prompt("Please enter country code:", "+84")
    if (inputCountryCode) {
      countryCode = inputCountryCode
    }

    // Input phone number
    let inputPhoneNumber = prompt("Please enter phone number:", "")
    if (inputPhoneNumber) {
      phoneNumber = inputPhoneNumber
    }

    if (countryCode && phoneNumber) {
      try {
        await updateUserProfile(MARKET_NAME, user?.id || "", {
          countryCode,
          phoneNumber,
        })
        alert("Update user profile successful!")
      } catch (error) {
        alert("Update user profile fail!")
      }
    } else {
      alert("Country code or Phone number is invalid!")
    }
  }

  const handleChangeSelectProductCode = (productCode: string) => {
    setSelectedProductCode(productCode)
  }

  const handleSelectedLanguage = (language: string) => {
    setSelectedLocale(language)
  }

  return (
    <BnplWrapper>
      <BnplBackground />
      <ProductListStyled className="product-list-wrapper">
        <div className="product-image-placeholder">
          <img src={spBackground} alt="" />

          <ProductContentWrapper className="product-content-wrapper">
            <ProductContent className="product-content">
              <ProductBlockWrapper className="product-block-wrapper">
                {renderProductBlock}
              </ProductBlockWrapper>
            </ProductContent>
          </ProductContentWrapper>

          <div className="payment-block">
            <div className="total-price">
              {formatCurrency(totalAmount.toString())} đ
            </div>
            <div className="button-controls">
              <div
                className="bnpl-btn"
                style={{
                  visibility: offers.length > 0 ? "visible" : "hidden",
                }}
                onClick={handleClickBnplWithIntent}
              >
                NHẬN HÀNG TRƯỚC TRẢ SAU<br></br>
                <p>
                  Cùng&nbsp;
                  <img
                    height={20}
                    src={CredifyLogo2}
                    alt="Creditfy"
                    className="logo__image--black"
                  ></img>
                  Credify
                </p>
              </div>
              <div className="next-btn" onClick={() => console.log("next")}>
                TIẾP TỤC
              </div>
            </div>
          </div>
        </div>
      </ProductListStyled>

      <SliderWrapperStyled>
        <div>BNPL with eKYC</div>&nbsp;
        <label className="switch">
          <input
            type="checkbox"
            checked={withEkyc}
            onChange={(e) => setWithEkyc(e.target.checked)}
          />
          <span className="slider round"></span>
        </label>
      </SliderWrapperStyled>
      <SliderWrapperStyled>
        <div>Open with redirect</div>&nbsp;
        <label className="switch">
          <input
            type="checkbox"
            checked={openWithRedirect}
            onChange={(e) => setOpenWithRedirect(e.target.checked)}
          />
          <span className="slider round"></span>
        </label>
      </SliderWrapperStyled>
      <LoginButton onClick={randomUser} style={{ marginTop: 10 }}>
        <LoginText>Random user</LoginText>
      </LoginButton>
      <IdWrapper>
        <CurentText>UserId: </CurentText>
        <IdInput
          ref={inputRef}
          value={idText.toString()}
          onChange={(e) => setIdText(e.target.value)}
        />
        <FetchInput type="button" value="FETCH" onClick={loadData} />
      </IdWrapper>
      <IdWrapper>
        <button onClick={updatePhoneNumber}>Update phone number</button>
      </IdWrapper>
      <ServiceInstanceWrapper>
        <button onClick={goToServiceInstance}>Service instance</button>
      </ServiceInstanceWrapper>
      <div>
        <ProductCodeSelect
          onChange={handleChangeSelectProductCode}
          datas={productCodes}
          title={"Select product code"}
        />
      </div>
      <div>
        <ProductCodeSelect
          onChange={handleSelectedLanguage}
          datas={LANGUAGES}
          title={"Select language"}
        />
      </div>
      <CredifyImageWrapper>
        <CredifyImage src={CredifyLogo} />
      </CredifyImageWrapper>
      <FullScreenLoading active={isLoading} text={``} />
      {showModal && (
        <PaymentSucceedModal setShowModal={setShowModal}></PaymentSucceedModal>
      )}
    </BnplWrapper>
  )
}

export { BnplPage }
