/*
 * Copyright (c) 2023 AccelByte Inc. All Rights Reserved
 * This is licensed software from AccelByte Inc, for limitations
 * and restrictions contact your company contract manager.
 */

import React, { StrictMode } from 'react'
import ReactDOMServer from 'react-dom/server'

import { routes } from './App'
import { Request as ExpressRequest } from 'express'

import { createStaticHandler, createStaticRouter, StaticRouterProvider } from 'react-router-dom/server'

// @ts-ignore
import { installGlobals } from '@remix-run/node'

// Polyfill Web Fetch API
installGlobals()

function createFetchRequest(req: ExpressRequest) {
  const origin = `${req.protocol}://${req.get('host')}`
  // Note: This had to take originalUrl into account for presumably vite's proxying
  const url = new URL(req.originalUrl || req.url, origin)

  const controller = new AbortController()
  req.on('close', () => controller.abort())

  const headers = new Headers()

  for (const [key, values] of Object.entries(req.headers)) {
    if (values) {
      if (Array.isArray(values)) {
        for (const value of values) {
          headers.append(key, value)
        }
      } else {
        headers.set(key, values)
      }
    }
  }

  const init: RequestInit = {
    method: req.method,
    headers,
    signal: controller.signal
  }

  if (req.method !== 'GET' && req.method !== 'HEAD') {
    init.body = req.body
  }

  return new Request(url.href)
}

export async function renderHtml(req: ExpressRequest) {
  const { query, dataRoutes } = createStaticHandler(routes)
  const fetchRequest = createFetchRequest(req)
  const context = await query(fetchRequest)

  // If we got a redirect response, short circuit and let our Express server
  // handle that directly
  if (context instanceof Response) {
    throw context
  }

  const router = createStaticRouter(dataRoutes, context)

  // try {
  return ReactDOMServer.renderToString(
    <StrictMode>
      <StaticRouterProvider router={router} context={context} />
    </StrictMode>
  )
  // } catch (err: any) {
  //   return err
  // }
}
