import { cx } from "class-variance-authority"
import { type ReactNode, Suspense } from "react"

import DiamondAddIcon from "@scandic-hotels/design-system/Icons/DiamondAddIcon"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"

import {
  SAS_EUROBONUS_TIER_TO_NAME_MAP,
  TIER_TO_FRIEND_MAP,
} from "@/constants/membershipLevels"
import { env } from "@/env/server"
import { getProfileWithExtendedPartnerData } from "@/lib/trpc/memoizedRequests"

import SectionContainer from "@/components/Section/Container"
import SectionHeader from "@/components/Section/Header"
import SectionLink from "@/components/Section/Link"
import SkeletonShimmer from "@/components/SkeletonShimmer"
import { getIntl } from "@/i18n"
import { getEurobonusMembership } from "@/utils/user"

import { UnlinkSAS } from "./UnlinkSAS"

import styles from "./linkedAccounts.module.css"

import type { UserLoyalty } from "@/types/user"

type Props = {
  title?: string
  link?: { href: string; text: string }
  subtitle?: string
}

export default async function SASLinkedAccount({
  title,
  subtitle,
  link,
}: Props) {
  if (!env.SAS_ENABLED) {
    return null
  }

  const intl = await getIntl()

  return (
    <div className={styles.container}>
      <SectionContainer>
        <SectionHeader link={link} preamble={subtitle} title={title} />
        <SectionLink link={link} variant="mobile" />
        <section className={styles.cardsContainer}>
          <Suspense fallback={<MatchedAccountInfoSkeleton />}>
            <MatchedAccountInfo />
          </Suspense>
        </section>
      </SectionContainer>
      <div className={styles.mutationSection}>
        <Typography variant="Body/Supporting text (caption)/smRegular">
          <p className={styles.caption}>
            <MaterialIcon icon="info" size={20} />
            {intl.formatMessage({
              defaultMessage:
                "Changes in your level match can take up to 24 hours to be displayed.",
            })}
          </p>
        </Typography>
        <UnlinkSAS />
      </div>
    </div>
  )
}

async function MatchedAccountInfo() {
  const user = await getProfileWithExtendedPartnerData()

  if (!user || "error" in user || !user.loyalty) {
    return null
  }

  const intl = await getIntl()

  const eurobonusMembership = getEurobonusMembership(user.loyalty)
  const friendsMembership = user.membership
  if (!eurobonusMembership || !friendsMembership) {
    return null
  }

  const sasLevelName =
    SAS_EUROBONUS_TIER_TO_NAME_MAP[
      eurobonusMembership.boostedTier || eurobonusMembership.tier
    ]
  const sasMembershipNumber = eurobonusMembership.membershipNumber
  const sasTierExpirationDate =
    eurobonusMembership.boostedTierExpires || eurobonusMembership.tierExpires

  const scandicLevelName = TIER_TO_FRIEND_MAP[friendsMembership.membershipLevel]
  const scandicExpirationDate = friendsMembership.tierExpirationDate

  const matchState = calculateMatchState(user.loyalty)

  return (
    <section className={styles.matchedAccountSection}>
      <div className={styles.accountDetails}>
        <div className={styles.stack}>
          <Label>
            {intl.formatMessage({
              defaultMessage: "Linked account",
            })}
          </Label>
          <Typography variant="Body/Paragraph/mdBold">
            <p>
              {intl.formatMessage({
                defaultMessage: "SAS EuroBonus",
              })}
            </p>
          </Typography>
        </div>
        <div className={styles.stack}>
          <Label>
            {intl.formatMessage({
              defaultMessage: "Level",
            })}
          </Label>
          <Typography variant="Body/Paragraph/mdBold">
            <p>{sasLevelName}</p>
          </Typography>
        </div>
        <div className={cx(styles.stack, styles.accountMemberNumber)}>
          <Label>
            {intl.formatMessage({
              defaultMessage: "Membership number",
            })}
          </Label>
          <Typography variant="Body/Paragraph/mdBold">
            {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
            <p className={styles.textRight}>EB{sasMembershipNumber}</p>
          </Typography>
        </div>
      </div>
      <div className={styles.tierMatchStatus}>
        <TierMatchMessage
          matchState={matchState}
          scandicLevelName={scandicLevelName}
          sasLevelName={sasLevelName}
        />
        <TierMatchExpiration
          matchState={matchState}
          sasExpirationDate={sasTierExpirationDate}
          scandicExpirationDate={scandicExpirationDate}
        />
      </div>
    </section>
  )
}

async function MatchedAccountInfoSkeleton() {
  const intl = await getIntl()

  return (
    <section className={styles.matchedAccountSection}>
      <div className={styles.accountDetails}>
        <div className={styles.stack}>
          <Label>
            {intl.formatMessage({
              defaultMessage: "Linked account",
            })}
          </Label>
          <Typography variant="Body/Paragraph/mdBold">
            <p>
              {intl.formatMessage({
                defaultMessage: "SAS EuroBonus",
              })}
            </p>
          </Typography>
        </div>
        <div className={styles.stack}>
          <Label>
            {intl.formatMessage({
              defaultMessage: "Level",
            })}
          </Label>
          <SkeletonShimmer width="6ch" height="24px" />
        </div>
        <div className={cx(styles.stack, styles.accountMemberNumber)}>
          <Label>
            {intl.formatMessage({
              defaultMessage: "Membership number",
            })}
          </Label>
          <SkeletonShimmer width="10ch" height="24px" />
        </div>
      </div>
      <div className={styles.tierMatchStatus}>
        <TierMatchMessageSkeleton />
      </div>
    </section>
  )
}

type TierMatchMessageProps = {
  matchState: MatchState
  scandicLevelName: string
  sasLevelName: string
}
async function TierMatchMessage({
  matchState,
  sasLevelName,
  scandicLevelName,
}: TierMatchMessageProps) {
  const intl = await getIntl()

  const messageValues = {
    sasLevelName: sasLevelName,
    scandicLevelName: scandicLevelName,
    sasMark: (text: ReactNode) => (
      <Typography variant="Body/Paragraph/mdBold">
        <span className={styles.sasMark}>{text}</span>
      </Typography>
    ),
    scandicMark: (text: ReactNode) => (
      <Typography variant="Body/Paragraph/mdBold">
        <span className={styles.scandicMark}>{text}</span>
      </Typography>
    ),
  }

  const messageMap: Record<MatchState, ReactNode> = {
    boostedBySAS: intl.formatMessage(
      {
        defaultMessage:
          "<sasMark>EuroBonus {sasLevelName}</sasMark> has upgraded your Scandic Friends level to <scandicMark>{scandicLevelName}</scandicMark>.",
      },
      messageValues
    ),
    boostedByScandic: intl.formatMessage(
      {
        defaultMessage:
          "Your Scandic Friends level <scandicMark>{scandicLevelName}</scandicMark> has upgraded you to <sasMark>EuroBonus {sasLevelName}</sasMark>.",
      },
      messageValues
    ),
    noBoost: intl.formatMessage(
      {
        defaultMessage:
          "<sasMark>EuroBonus {sasLevelName}</sasMark> and <scandicMark>{scandicLevelName}</scandicMark> are equally matched. Level up in one of your memberships to qualify for an upgrade!",
      },
      messageValues
    ),
  }

  const iconMap: Record<MatchState, ReactNode> = {
    boostedBySAS: <DiamondAddIcon size={20} />,
    boostedByScandic: <DiamondAddIcon size={20} />,
    noBoost: <MaterialIcon icon="link" size={20} />,
  }

  return (
    <div className={styles.stack}>
      <Label>
        {intl.formatMessage({
          defaultMessage: "Level match status",
        })}
      </Label>
      <div className={styles.tierMatchText}>
        <div className={styles.iconWrapper}>{iconMap[matchState]}</div>
        <Typography variant="Body/Paragraph/mdRegular">
          <p>{messageMap[matchState]}</p>
        </Typography>
      </div>
    </div>
  )
}

async function TierMatchMessageSkeleton() {
  const intl = await getIntl()

  return (
    <div className={styles.stack}>
      <Label>
        {intl.formatMessage({
          defaultMessage: "Level match status",
        })}
      </Label>
      <div className={styles.tierMatchText}>
        <SkeletonShimmer width="250px" height="24px" />
      </div>
    </div>
  )
}

type TierMatchExpirationProps = {
  matchState: MatchState
  sasExpirationDate: string | null
  scandicExpirationDate: string | undefined
}
async function TierMatchExpiration({
  matchState,
  sasExpirationDate,
  scandicExpirationDate,
}: TierMatchExpirationProps) {
  if (matchState === "noBoost") {
    return null
  }

  const intl = await getIntl()

  const displayedExpirationDate =
    matchState === "boostedBySAS" ? scandicExpirationDate : sasExpirationDate

  if (!displayedExpirationDate) {
    return null
  }

  return (
    <div className={cx(styles.stack, styles.textRight)}>
      <Label>
        {intl.formatMessage({
          defaultMessage: "Upgrade valid until",
        })}
      </Label>
      <Typography variant="Body/Paragraph/mdBold">
        <p>{displayedExpirationDate}</p>
      </Typography>
    </div>
  )
}

function Label({ children }: { children: ReactNode }) {
  return (
    <Typography variant="Tag/sm">
      <p className={styles.label}>{children}</p>
    </Typography>
  )
}

type MatchState = "boostedBySAS" | "boostedByScandic" | "noBoost"
function calculateMatchState(loyalty: UserLoyalty): MatchState {
  const eurobonusMembership = getEurobonusMembership(loyalty)
  if (eurobonusMembership?.boostedByScandic) return "boostedByScandic"

  if (!loyalty.tierBoostedBy) return "noBoost"
  if (loyalty.tierBoostedBy === "SAS_EB") return "boostedBySAS"

  return "noBoost"
}
