import * as api from "@/lib/api"
import {
  badRequestError,
  forbiddenError,
  internalServerError,
  notFound,
  unauthorizedError,
} from "@/server/errors/trpc"
import { protectedProcedure, router } from "@/server/trpc"

import { staysInput } from "./input"
import { getStaysSchema, getUserSchema } from "./output"
import { benefits, extendedUser, nextLevelPerks } from "./temp"

function fakingRequest<T>(payload: T): Promise<T> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(payload)
    }, 1500)
  })
}

export const userQueryRouter = router({
  get: protectedProcedure.query(async function ({ ctx }) {
    const apiResponse = await api.get(api.endpoints.v1.profile, {
      cache: "no-store",
      headers: {
        Authorization: `Bearer ${ctx.session.token.access_token}`,
      },
    })

    if (!apiResponse.ok) {
      switch (apiResponse.status) {
        case 400:
          throw badRequestError(apiResponse)
        case 401:
          throw unauthorizedError(apiResponse)
        case 403:
          throw forbiddenError(apiResponse)
        default:
          throw internalServerError(apiResponse)
      }
    }

    const apiJson = await apiResponse.json()
    if (!apiJson.data?.attributes) {
      throw notFound(apiJson)
    }

    const verifiedData = getUserSchema.safeParse(apiJson.data.attributes)
    if (!verifiedData.success) {
      throw internalServerError(verifiedData.error)
    }

    return {
      ...extendedUser,
      ...verifiedData.data,
      name: `${verifiedData.data.firstName} ${verifiedData.data.lastName}`,
    }
  }),

  benefits: router({
    current: protectedProcedure.query(async function (opts) {
      // TODO: Make request to get user data from Scandic API
      return await fakingRequest<typeof benefits>(benefits)
    }),
    nextLevel: protectedProcedure.query(async function (opts) {
      // TODO: Make request to get user data from Scandic API
      return await fakingRequest<typeof nextLevelPerks>(nextLevelPerks)
    }),
  }),

  stays: router({
    previous: protectedProcedure
      .input(staysInput)
      .query(async ({ ctx, input }) => {
        const { limit, cursor } = input

        const params = new URLSearchParams()
        params.set("limit", limit.toString())

        if (cursor) {
          params.set("offset", cursor.toString())
        }

        const apiResponse = await api.get(
          api.endpoints.v1.previousStays,
          {
            headers: {
              Authorization: `Bearer ${ctx.session.token.access_token}`,
            },
          },
          params
        )

        if (!apiResponse.ok) {
          switch (apiResponse.status) {
            case 400:
              throw badRequestError(apiResponse)
            case 401:
              throw unauthorizedError(apiResponse)
            case 403:
              throw forbiddenError(apiResponse)
            default:
              throw internalServerError(apiResponse)
          }
        }

        const apiJson = await apiResponse.json()
        if (!apiJson.data?.length) {
          throw notFound(apiJson)
        }

        const verifiedData = getStaysSchema.safeParse(apiJson)
        if (!verifiedData.success) {
          throw internalServerError(verifiedData.error)
        }

        const nextCursor =
          verifiedData.data.links &&
          verifiedData.data.links.offset < verifiedData.data.links.totalCount
            ? verifiedData.data.links.offset
            : undefined

        return {
          data: verifiedData.data.data,
          nextCursor,
        }
      }),

    upcoming: protectedProcedure
      .input(staysInput)
      .query(async ({ ctx, input }) => {
        const { limit, cursor } = input

        const params = new URLSearchParams()
        params.set("limit", limit.toString())

        if (cursor) {
          params.set("offset", cursor.toString())
        }

        const apiResponse = await api.get(
          api.endpoints.v1.upcomingStays,
          {
            headers: {
              Authorization: `Bearer ${ctx.session.token.access_token}`,
            },
          },
          params
        )

        if (!apiResponse.ok) {
          switch (apiResponse.status) {
            case 400:
              throw badRequestError(apiResponse)
            case 401:
              throw unauthorizedError(apiResponse)
            case 403:
              throw forbiddenError(apiResponse)
            default:
              throw internalServerError(apiResponse)
          }
        }

        const apiJson = await apiResponse.json()
        const verifiedData = getStaysSchema.safeParse(apiJson)
        if (!verifiedData.success) {
          throw internalServerError(verifiedData.error)
        }

        const nextCursor =
          verifiedData.data.links &&
          verifiedData.data.links.offset < verifiedData.data.links.totalCount
            ? verifiedData.data.links.offset
            : undefined

        return {
          data: verifiedData.data.data,
          nextCursor,
        }
      }),
  }),
})
