import * as Sentry from "@sentry/nextjs"
import { z } from "zod"

import * as api from "@/lib/api"
import { protectedProcedure } from "@/server/trpc"

import { getOTPState } from "./otp/getOTPState"
import { getSasToken } from "./getSasToken"

const outputSchema = z.object({
  linkingState: z.enum([
    "linked",
    "alreadyLinked",
    "dateOfBirthMismatch",
    "nameNotMatched",
    "blockedForRelink",
    "accountToNew",
    "error",
  ]),
})

export const linkAccount = protectedProcedure
  .output(outputSchema)
  .mutation(async function ({ ctx }) {
    const sasAuthToken = await getSasToken()
    const { referenceId } = await getOTPState()

    console.log("[SAS] link account")

    const apiResponse = await api.post(api.endpoints.v1.Profile.link, {
      headers: {
        Authorization: `Bearer ${ctx.session.token.access_token}`,
      },
      body: {
        partner: "sas_eb",
        tocDate: getCurrentDateWithoutTime(),
        partnerSpecific: {
          eurobonusAccessToken: sasAuthToken,
          eurobonusOtpReferenceId: referenceId,
        },
      },
    })

    const linkedAndBoosted = apiResponse.status === 200
    const linkedWithoutBoost = apiResponse.status === 204
    const linkedWithUnknownBoost = apiResponse.status === 202
    const linked =
      linkedAndBoosted || linkedWithoutBoost || linkedWithUnknownBoost

    if (linked) {
      console.log("[SAS] link account done")
      return { linkingState: "linked" }
    }

    if (apiResponse.status === 400) {
      const result = await apiResponse.json()
      const data = badRequestSchema.safeParse(result)
      if (!data.success) {
        const linkAccountBadRequestSchemaError = `[SAS] failed to parse link account bad request schema ${JSON.stringify(data.error)}`
        console.error(linkAccountBadRequestSchemaError)
        Sentry.captureMessage(linkAccountBadRequestSchemaError)
        return { linkingState: "error" }
      }

      console.log("[SAS] link account error with response", result)

      const { errors } = data.data

      if (errors.some((x) => x.code === "BirthDateNotMatched")) {
        return { linkingState: "dateOfBirthMismatch" }
      }
      if (errors.some((x) => x.code === "BlockedForRelink")) {
        return { linkingState: "blockedForRelink" }
      }
      if (errors.some((x) => x.code === "AccountToNew")) {
        return { linkingState: "accountToNew" }
      }
      if (errors.some((x) => x.code === "NameNotMatched")) {
        return { linkingState: "nameNotMatched" }
      }
      if (errors.some((x) => x.code === "AlreadyLinked")) {
        return { linkingState: "alreadyLinked" }
      }

      return { linkingState: "error" }
    }

    if (apiResponse.status === 409) {
      return { linkingState: "alreadyLinked" }
    }

    const errorMessage = `[SAS] link account error with status code ${apiResponse.status} and response ${await apiResponse.text()}`
    console.warn(errorMessage)
    Sentry.captureMessage(errorMessage)
    return { linkingState: "error" }
  })

function getCurrentDateWithoutTime() {
  return new Date().toISOString().slice(0, 10)
}

const badRequestSchema = z.object({
  errors: z.array(
    z.object({
      code: z.enum([
        "BirthDateNotMatched",
        "NameNotMatched",
        "AlreadyLinked",
        "BlockedForRelink",
        "AccountToNew",
        "UnknownReason",
      ]),
      details: z.string().optional(),
    })
  ),
})
