import { NextResponse } from 'next/server'
import { MiddlewareRequest, NextRequest } from '@netlify/next'

// Next.js replaces this with a stub polyfill. This import is just to test that stub.
import pointlessFetch from 'isomorphic-unfetch'

export async function middleware(req: NextRequest) {
  let response
  const { pathname } = req.nextUrl

  const request = new MiddlewareRequest(req)
  if (pathname.startsWith('/static')) {
    // Unlike NextResponse.next(), this actually sends the request to the origin
    const res = await request.next()
    const message = `This was static but has been transformed in ${req.geo?.city}`

    // Transform the response HTML and props
    res.replaceText('p[id=message]', message)
    res.setPageProp('message', message)
    res.setPageProp('showAd', true)

    res.headers.set('x-modified-edge', 'true')
    res.headers.set('x-is-deno', 'Deno' in globalThis ? 'true' : 'false')
    return res
  }

  if (pathname.startsWith('/api/hello')) {
    // Add a header to the request
    req.headers.set('x-hello', 'world')
    return request.next()
  }

  if (pathname.startsWith('/api/geo')) {
    req.headers.set('x-geo-country', req.geo.country)
    req.headers.set('x-geo-region', req.geo.region)
    req.headers.set('x-geo-city', req.geo.city)
    req.headers.set('x-geo-longitude', req.geo.longitude)
    req.headers.set('x-geo-latitude', req.geo.latitude)
    req.headers.set('x-geo-timezone', req.geo.timezone)

    return request.next()
  }

  if (pathname.startsWith('/headers')) {
    // Add a header to the rewritten request
    req.headers.set('x-hello', 'world')
    return request.rewrite('/api/hello')
  }

  if (pathname.startsWith('/cookies')) {
    response = NextResponse.next()
    response.cookies.set('netlifyCookie', 'true')
    return response
  }

  if (pathname.startsWith('/conditional')) {
    response = NextResponse.next()
    response.headers.set('x-modified-edge', 'true')
    response.headers.set('x-is-deno', 'Deno' in globalThis ? 'true' : 'false')
    return response
  }

  if (pathname.startsWith('/shows')) {
    if (pathname.startsWith('/shows/222')) {
      response = NextResponse.next()
      const res = await pointlessFetch('http://www.example.com/')
      response.headers.set('x-example-server', res.headers.get('server'))
    }

    if (pathname.startsWith('/shows/rewrite-absolute')) {
      response = NextResponse.rewrite(new URL('/shows/100', req.url))
      response.headers.set('x-modified-in-rewrite', 'true')
    }
    if (pathname.startsWith('/shows/rewrite-external')) {
      response = NextResponse.rewrite('http://example.com/')
      response.headers.set('x-modified-in-rewrite', 'true')
    }
    if (pathname.startsWith('/shows/rewriteme')) {
      const url = req.nextUrl.clone()
      url.pathname = '/shows/100'
      response = NextResponse.rewrite(url)
      response.headers.set('x-modified-in-rewrite', 'true')
    }

    if (pathname.startsWith('/shows/redirectme')) {
      const url = req.nextUrl.clone()
      url.pathname = '/shows/100'
      response = NextResponse.redirect(url)
    }

    if (pathname.startsWith('/shows/redirectexternal')) {
      response = NextResponse.redirect('http://example.com/')
    }

    if (!response) {
      response = NextResponse.next()
    }

    if (pathname.startsWith('/shows/static')) {
      response.headers.set('x-middleware-date', new Date().toISOString())
    }

    response.headers.set('x-modified-edge', 'true')
    response.headers.set('x-is-deno', 'Deno' in globalThis ? 'true' : 'false')

    return response
  }
}

export const config = {
  matcher: [
    '/api/:all*',
    '/headers',
    { source: '/static' },
    { source: '/cookies' },
    { source: '/shows/((?!99|88).*)' },
    {
      source: '/conditional',
      has: [
        {
          type: 'header',
          key: 'x-my-header',
          value: 'my-value',
        },
      ],
    },
  ],
}
