// @ts-ignore
const unfetch = require('unfetch/dist/unfetch.js')
// @ts-ignore
const isComponentSpec = () => Cypress.spec.specType === 'component'

// When running component specs, we cannot allow "cy.visit"
// because it will wipe out our preparation work, and does not make much sense
// thus we overwrite "cy.visit" to throw an error
Cypress.Commands.overwrite('visit', (visit, ...args: any[]) => {
  if (isComponentSpec()) {
    throw new Error(
      'cy.visit from a component spec is not allowed\n' +
        'see https://github.com/bahmutov/@cypress/react/issues/286',
    )
  } else {
    // allow regular visit to proceed
    return visit(...args)
  }
})

/** Initialize an empty document with root element */
function renderTestingPlatform () {
  // Let's mount components under a new div with this id
  const rootId = 'cypress-root'

  const document = cy.state('document') as Document

  if (document.getElementById(rootId)) {
    return
  }

  const rootNode = document.createElement('div')

  rootNode.setAttribute('id', rootId)
  document.getElementsByTagName('body')[0].prepend(rootNode)

  const selector = `#${rootId}`

  return cy.get(selector, { log: false })
}

/**
 * Replaces window.fetch with a polyfill based on XMLHttpRequest
 * that Cypress can spy on and stub
 * @see https://www.cypress.io/blog/2020/06/29/experimental-fetch-polyfill/
 */
function polyfillFetchIfNeeded () {
  // @ts-ignore
  if (Cypress.config('experimentalFetchPolyfill')) {
    if (!cy.state('fetchPolyfilled')) {
      // TypeScript v4 checks if the property to be deleted is optional
      // @ts-ignore
      delete window.fetch
      window.fetch = unfetch
      // @ts-ignore
      cy.state('fetchPolyfilled', true)
    }
  }
}

before(() => {
  if (!isComponentSpec()) {
    return
  }

  polyfillFetchIfNeeded()
  renderTestingPlatform()
})

/**
 * Remove any style or extra link elements from the iframe placeholder
 * left from any previous test
 *
 */
function cleanupStyles () {
  if (!isComponentSpec()) {
    return
  }

  const document = cy.state('document') as Document

  const styles = document.body.querySelectorAll('style')

  styles.forEach((styleElement) => {
    if (styleElement.parentElement) {
      styleElement.parentElement.removeChild(styleElement)
    }
  })

  const links = document.body.querySelectorAll('link[rel=stylesheet]')

  links.forEach((link) => {
    if (link.parentElement) {
      link.parentElement.removeChild(link)
    }
  })
}

beforeEach(cleanupStyles)
