import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { getRedboxSource, hasRedbox, renderViaHTTP } from 'next-test-utils'
import cheerio from 'cheerio'
import path from 'path'
import webdriver from 'next-webdriver'

describe('app dir next-font', () => {
  const isDev = (global as any).isNextDev
  //if ((global as any).isNextDeploy) {
  //  it('should skip next deploy for now', () => {})
  //  return
  //}

  let next: NextInstance

  beforeAll(async () => {
    next = await createNext({
      files: new FileRef(path.join(__dirname, 'next-font')),
      dependencies: {
        '@next/font': 'canary',
        react: 'experimental',
        'react-dom': 'experimental',
      },
      skipStart: true,
    })
    await next.start()
  }, 600000)
  afterAll(() => next.destroy())

  describe('import values', () => {
    it('should have correct values at /', async () => {
      const html = await renderViaHTTP(next.url, '/')
      const $ = cheerio.load(html)

      // layout
      expect(JSON.parse($('#root-layout').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        variable: expect.stringMatching(/^__variable_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font1_.{6}'$/),
        },
      })
      // page
      expect(JSON.parse($('#root-page').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        variable: expect.stringMatching(/^__variable_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font2_.{6}'$/),
        },
      })
      // Comp
      expect(JSON.parse($('#root-comp').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font3_.{6}'$/),
          fontStyle: 'italic',
          fontWeight: 900,
        },
      })
    })

    it('should have correct values at /client', async () => {
      const html = await renderViaHTTP(next.url, '/client')
      const $ = cheerio.load(html)

      // root layout
      expect(JSON.parse($('#root-layout').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        variable: expect.stringMatching(/^__variable_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font1_.{6}'$/),
        },
      })

      // layout
      expect(JSON.parse($('#client-layout').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font4_.{6}'$/),
          fontWeight: 100,
        },
      })
      // page
      expect(JSON.parse($('#client-page').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font5_.{6}'$/),
          fontStyle: 'italic',
        },
      })
      // Comp
      expect(JSON.parse($('#client-comp').text())).toEqual({
        className: expect.stringMatching(/^__className_.{6}$/),
        style: {
          fontFamily: expect.stringMatching(/^'__font6_.{6}'$/),
        },
      })
    })
  })

  describe('computed styles', () => {
    it('should have correct styles at /', async () => {
      const browser = await webdriver(next.url, '/')

      // layout
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-layout")).fontFamily')).toMatch(
        /^__font1_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-layout")).fontWeight')).toBe('400')
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-layout")).fontStyle')).toBe('normal')

      // page
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-page")).fontFamily')).toMatch(
        /^__font2_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-page")).fontWeight')).toBe('400')
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-page")).fontStyle')).toBe('normal')

      // Comp
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-comp")).fontFamily')).toMatch(
        /^__font3_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-comp")).fontWeight')).toBe('900')
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-comp")).fontStyle')).toBe('italic')
    })

    it('should have correct styles at /client', async () => {
      const browser = await webdriver(next.url, '/client')

      // root layout
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-layout")).fontFamily')).toMatch(
        /^__font1_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-layout")).fontWeight')).toBe('400')
      expect(await browser.eval('getComputedStyle(document.querySelector("#root-layout")).fontStyle')).toBe('normal')

      // layout
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-layout")).fontFamily')).toMatch(
        /^__font4_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-layout")).fontWeight')).toBe('100')
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-layout")).fontStyle')).toBe('normal')

      // page
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-page")).fontFamily')).toMatch(
        /^__font5_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-page")).fontWeight')).toBe('400')
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-page")).fontStyle')).toBe('italic')

      // Comp
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-comp")).fontFamily')).toMatch(
        /^__font6_.{6}$/,
      )
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-comp")).fontWeight')).toBe('400')
      expect(await browser.eval('getComputedStyle(document.querySelector("#client-comp")).fontStyle')).toBe('normal')
    })
  })

  if (!isDev) {
    describe('preload', () => {
      it('should preload correctly with server components', async () => {
        const html = await renderViaHTTP(next.url, '/')
        const $ = cheerio.load(html)

        // Preconnect
        expect($('link[rel="preconnect"]').length).toBe(0)

        expect($('link[as="font"]').length).toBe(3)
        expect($('link[as="font"]').get(0).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/e9b9dc0d8ba35f48.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
        expect($('link[as="font"]').get(1).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/b61859a50be14c53.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
        expect($('link[as="font"]').get(2).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/b2104791981359ae.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
      })

      it('should preload correctly with client components', async () => {
        const html = await renderViaHTTP(next.url, '/client')
        const $ = cheerio.load(html)

        // Preconnect
        expect($('link[rel="preconnect"]').length).toBe(0)

        expect($('link[as="font"]').length).toBe(3)
        // From root layout
        expect($('link[as="font"]').get(0).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/e9b9dc0d8ba35f48.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })

        expect($('link[as="font"]').get(1).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/e1053f04babc7571.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
        expect($('link[as="font"]').get(2).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/feab2c68f2a8e9a4.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
      })

      it('should preload correctly with layout using fonts', async () => {
        const html = await renderViaHTTP(next.url, '/layout-with-fonts')
        const $ = cheerio.load(html)

        // Preconnect
        expect($('link[rel="preconnect"]').length).toBe(0)

        expect($('link[as="font"]').length).toBe(2)
        // From root layout
        expect($('link[as="font"]').get(0).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/e9b9dc0d8ba35f48.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })

        expect($('link[as="font"]').get(1).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/75c5faeeb9c86969.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
      })

      it('should preload correctly with page using fonts', async () => {
        const html = await renderViaHTTP(next.url, '/page-with-fonts')
        const $ = cheerio.load(html)

        // Preconnect
        expect($('link[rel="preconnect"]').length).toBe(0)

        expect($('link[as="font"]').length).toBe(2)
        // From root layout
        expect($('link[as="font"]').get(0).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/e9b9dc0d8ba35f48.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })

        expect($('link[as="font"]').get(1).attribs).toEqual({
          as: 'font',
          crossorigin: '',
          href: '/_next/static/media/568e4c6d8123c4d6.p.woff2',
          rel: 'preload',
          type: 'font/woff2',
        })
      })
    })
  }

  if (isDev) {
    describe('Dev errors', () => {
      it('should recover on font loader error', async () => {
        const browser = await webdriver(next.url, '/')
        const font1Content = await next.readFile('fonts/index.js')

        // Break file
        await next.patchFile('fonts/index.js', font1Content.replace('./font1.woff2', './does-not-exist.woff2'))
        expect(await hasRedbox(browser, true)).toBeTrue()
        expect(await getRedboxSource(browser)).toInclude("Can't resolve './does-not-exist.woff2'")

        // Fix file
        await next.patchFile('fonts/index.js', font1Content)
        await browser.waitForElementByCss('#root-page')
      })
    })
  }
})
