import { cookies } from "next/headers"
import { redirect, RedirectType } from "next/navigation"
import { z } from "zod"

import { serverClient } from "@/lib/trpc/server"

import { getIntl } from "@/i18n"
import { safeTry } from "@/utils/safeTry"

import { SAS_TOKEN_STORAGE_KEY } from "../sasUtils"
import OneTimePasswordForm from "./OneTimePasswordForm"

import type { LangParams, PageArgs, SearchParams } from "@/types/params"
import type { Lang } from "@/constants/languages"

const searchParamsSchema = z.object({
  intent: z.enum(["link"]),
  to: z.string(),
  error: z.enum(["invalidCode"]).optional(),
})

export default async function SASxScandicOneTimePasswordPage({
  searchParams,
  params,
}: PageArgs<LangParams> & SearchParams) {
  const intl = await getIntl()
  const cookieStore = cookies()
  const tokenCookie = cookieStore.get(SAS_TOKEN_STORAGE_KEY)

  const result = searchParamsSchema.safeParse(searchParams)
  if (!result.success) {
    throw new Error("Invalid search params")
  }
  const { intent, to, error } = result.data

  if (!verifyTokenValidity(tokenCookie?.value)) {
    redirect(`/${params.lang}/sas-x-scandic/login?intent=${intent}`)
  }

  const errors = {
    invalidCode: intl.formatMessage({
      id: "The code you’ve entered is incorrect.",
    }),
  }

  async function handleOtpVerified({ otp }: { otp: string }) {
    "use server"

    const [data, error] = await safeTry(
      serverClient().partner.sas.verifyOtp({ otp })
    )

    // TODO correct status?
    // TODO handle all errors
    // STATUS === VERIFIED => ok
    // STATUS === ABUSED => otpRetryCount > otpMaxRetryCount
    if (error || data?.status !== "VERIFIED") {
      const search = new URLSearchParams({
        ...searchParams,
        error: "invalidCode",
      }).toString()

      redirect(`/${params.lang}/sas-x-scandic/otp?${search}`)
    }

    switch (intent) {
      case "link":
        return handleLinkAccount({ lang: params.lang })
      default:
        throw new Error("")
    }
  }

  return (
    <OneTimePasswordForm
      heading={intl.formatMessage({ id: "Verification code" })}
      ingress={intl.formatMessage<React.ReactNode>(
        {
          id: "Please enter the code sent to <maskedContactInfo></maskedContactInfo> in order to confirm your account linking.",
        },
        {
          maskedContactInfo: () => (
            <>
              <br />
              <strong>{to}</strong>
              <br />
            </>
          ),
        }
      )}
      footnote={intl.formatMessage({
        id: "This verifcation is needed for additional security.",
      })}
      otpLength={6}
      onSubmit={handleOtpVerified}
      error={error ? errors[error] : undefined}
    />
  )
}

function verifyTokenValidity(token: string | undefined) {
  if (!token) {
    return false
  }

  try {
    const decoded = JSON.parse(atob(token.split(".")[1]))
    const expiry = decoded.exp * 1000
    return Date.now() < expiry
  } catch (error) {
    return false
  }
}

async function handleLinkAccount({ lang }: { lang: Lang }) {
  const [res, error] = await safeTry(serverClient().partner.sas.linkAccount())
  if (!res || error) {
    console.error("[SAS] link account error", error)
    redirect(`/${lang}/sas-x-scandic/error?errorCode=link_error`)
  }

  console.log("[SAS] link account response", res)
  switch (res.linkingState) {
    case "linked":
      redirect(`/${lang}/sas-x-scandic/link/success`, RedirectType.replace)
      break
  }
}
