import { metrics } from "@opentelemetry/api"

import * as api from "@/lib/api"
import { getVerifiedUser } from "@/server/routers/user/query"
import { router, safeProtectedServiceProcedure } from "@/server/trpc"

import { getMembership } from "@/utils/user"

import { createBookingInput } from "./input"
import { createBookingSchema } from "./output"

import type { Session } from "next-auth"

const meter = metrics.getMeter("trpc.bookings")
const createBookingCounter = meter.createCounter("trpc.bookings.create")
const createBookingSuccessCounter = meter.createCounter(
  "trpc.bookings.create-success"
)
const createBookingFailCounter = meter.createCounter(
  "trpc.bookings.create-fail"
)

async function getMembershipNumber(
  session: Session | null
): Promise<string | undefined> {
  if (!session) return undefined

  const verifiedUser = await getVerifiedUser({ session })
  if (!verifiedUser || "error" in verifiedUser) {
    return undefined
  }

  const membership = getMembership(verifiedUser.data.memberships)
  return membership?.membershipNumber
}

export const bookingMutationRouter = router({
  create: safeProtectedServiceProcedure
    .input(createBookingInput)
    .mutation(async function ({ ctx, input }) {
      const accessToken = ctx.session?.token.access_token ?? ctx.serviceToken
      const { checkInDate, checkOutDate, hotelId } = input

      const loggingAttributes = {
        membershipNumber: await getMembershipNumber(ctx.session),
        checkInDate,
        checkOutDate,
        hotelId,
      }

      createBookingCounter.add(1, { hotelId, checkInDate, checkOutDate })

      console.info(
        "api.booking.create start",
        JSON.stringify({
          query: loggingAttributes,
        })
      )
      const headers = {
        Authorization: `Bearer ${accessToken}`,
      }

      const apiResponse = await api.post(api.endpoints.v1.Booking.bookings, {
        headers,
        body: input,
      })

      if (!apiResponse.ok) {
        const text = await apiResponse.text()
        createBookingFailCounter.add(1, {
          hotelId,
          checkInDate,
          checkOutDate,
          error_type: "http_error",
          error: JSON.stringify({
            status: apiResponse.status,
          }),
        })
        console.error(
          "api.booking.create error",
          JSON.stringify({
            query: loggingAttributes,
            error: {
              status: apiResponse.status,
              statusText: apiResponse.statusText,
              error: text,
            },
          })
        )
        return null
      }

      const apiJson = await apiResponse.json()
      const verifiedData = createBookingSchema.safeParse(apiJson)
      if (!verifiedData.success) {
        createBookingFailCounter.add(1, {
          hotelId,
          checkInDate,
          checkOutDate,
          error_type: "validation_error",
        })

        console.error(
          "api.booking.create validation error",
          JSON.stringify({
            query: loggingAttributes,
            error: verifiedData.error,
          })
        )
        return null
      }

      createBookingSuccessCounter.add(1, {
        hotelId,
        checkInDate,
        checkOutDate,
      })

      console.info(
        "api.booking.create success",
        JSON.stringify({
          query: loggingAttributes,
        })
      )
      return verifiedData.data
    }),
})
