import { assert } from '@open-wc/testing'
import { findElementInShadowRoots } from '../../src/lib/Dom.js'

describe('lib', () => {
  describe('Dom', () => {
    describe('findElementInShadowRoots', () => {
      let container: HTMLDivElement

      beforeEach(() => {
        container = document.createElement('div')
        container.id = 'test-container'
        document.body.appendChild(container)
      })

      afterEach(() => {
        document.body.removeChild(container)
      })

      it('finds element in document root', () => {
        const element = document.createElement('div')
        element.id = 'test-element'
        container.appendChild(element)

        const fromElement = document.createElement('div')
        container.appendChild(fromElement)

        const result = findElementInShadowRoots('test-element', fromElement)
        assert.equal(result, element)
      })

      it('returns null when element is not found', () => {
        const fromElement = document.createElement('div')
        container.appendChild(fromElement)

        const result = findElementInShadowRoots('non-existent', fromElement)
        assert.isNull(result)
      })

      it('finds element in parent shadow root', () => {
        // Create a custom element with shadow root
        const shadowHost = document.createElement('div')
        const shadowRoot = shadowHost.attachShadow({ mode: 'open' })
        // Add target element to shadow root
        const targetElement = document.createElement('div')
        targetElement.id = 'shadow-element'
        shadowRoot.appendChild(targetElement)

        // Add shadow host to container
        container.appendChild(shadowHost)

        // Create a child element inside the shadow root to search from
        const fromElement = document.createElement('div')
        shadowRoot.appendChild(fromElement)
        const result = findElementInShadowRoots('shadow-element', fromElement)
        assert.ok(result)
        assert.equal(result.id, 'shadow-element')
      })

      it('finds element in nested shadow roots', () => {
        // Create outer shadow host
        const outerShadowHost = document.createElement('div')
        outerShadowHost.id = 'outer-shadow-host'
        const outerShadowRoot = outerShadowHost.attachShadow({ mode: 'open' })

        // Create inner shadow host inside outer shadow root
        const innerShadowHost = document.createElement('div')
        innerShadowHost.id = 'inner-shadow-host'
        const innerShadowRoot = innerShadowHost.attachShadow({ mode: 'open' })
        outerShadowRoot.appendChild(innerShadowHost)

        // Add target element to outer shadow root
        const targetElement = document.createElement('div')
        targetElement.id = 'nested-element'
        outerShadowRoot.appendChild(targetElement)

        // Add container to document
        container.appendChild(outerShadowHost)

        // Search from element in inner shadow root
        const fromElement = document.createElement('div')
        fromElement.id = 'search-from'
        innerShadowRoot.appendChild(fromElement)

        const result = findElementInShadowRoots('nested-element', fromElement)
        assert.equal(result, targetElement)
      })

      it('searches through multiple shadow root levels', () => {
        // Create a deeply nested shadow structure
        const level1Host = document.createElement('div')
        const level1Shadow = level1Host.attachShadow({ mode: 'open' })

        const level2Host = document.createElement('div')
        const level2Shadow = level2Host.attachShadow({ mode: 'open' })
        level1Shadow.appendChild(level2Host)

        const level3Host = document.createElement('div')
        const level3Shadow = level3Host.attachShadow({ mode: 'open' })
        level2Shadow.appendChild(level3Host)

        // Add target element at level 1
        const targetElement = document.createElement('div')
        targetElement.id = 'deep-element'
        level1Shadow.appendChild(targetElement)

        container.appendChild(level1Host)

        // Search from deepest level
        const fromElement = document.createElement('div')
        level3Shadow.appendChild(fromElement)

        const result = findElementInShadowRoots('deep-element', fromElement)
        assert.equal(result, targetElement)
      })

      it('prefers document element over shadow root element', () => {
        // Create element in document
        const documentElement = document.createElement('div')
        documentElement.id = 'duplicate-id'
        documentElement.textContent = 'document'
        container.appendChild(documentElement)

        // Create shadow host with element with same ID
        const shadowHost = document.createElement('div')
        const shadowRoot = shadowHost.attachShadow({ mode: 'open' })

        const shadowElement = document.createElement('div')
        shadowElement.id = 'duplicate-id'
        shadowElement.textContent = 'shadow'
        shadowRoot.appendChild(shadowElement)

        container.appendChild(shadowHost)

        const fromElement = document.createElement('div')
        shadowRoot.appendChild(fromElement)

        const result = findElementInShadowRoots('duplicate-id', fromElement)
        assert.equal(result, documentElement)
        assert.isNotNull(result)
        assert.equal(result.textContent, 'document')
      })

      it('handles elements without parent', () => {
        const isolatedElement = document.createElement('div')

        const result = findElementInShadowRoots('test-id', isolatedElement)
        assert.isNull(result)
      })

      it('handles shadow root host traversal', () => {
        // Create a shadow host
        const shadowHost = document.createElement('div')
        const shadowRoot = shadowHost.attachShadow({ mode: 'open' })
        container.appendChild(shadowHost)

        // Add target element to container (outside shadow)
        const targetElement = document.createElement('div')
        targetElement.id = 'outside-shadow'
        container.appendChild(targetElement)

        // Search from inside shadow root
        const fromElement = document.createElement('div')
        shadowRoot.appendChild(fromElement)

        const result = findElementInShadowRoots('outside-shadow', fromElement)
        assert.equal(result, targetElement)
      })

      it('handles elements in current shadow root', () => {
        const shadowHost = document.createElement('div')
        const shadowRoot = shadowHost.attachShadow({ mode: 'open' })
        container.appendChild(shadowHost)

        // Add target element to same shadow root
        const targetElement = document.createElement('div')
        targetElement.id = 'same-shadow'
        shadowRoot.appendChild(targetElement)

        // Add search element to same shadow root
        const fromElement = document.createElement('div')
        shadowRoot.appendChild(fromElement)

        const result = findElementInShadowRoots('same-shadow', fromElement)
        assert.equal(result, targetElement)
      })

      it('handles complex shadow DOM structure with mixed content', () => {
        // Create complex structure: document -> shadow1 -> regular div -> shadow2
        const shadow1Host = document.createElement('div')
        const shadow1Root = shadow1Host.attachShadow({ mode: 'open' })
        container.appendChild(shadow1Host)

        const regularDiv = document.createElement('div')
        shadow1Root.appendChild(regularDiv)

        const shadow2Host = document.createElement('div')
        const shadow2Root = shadow2Host.attachShadow({ mode: 'open' })
        regularDiv.appendChild(shadow2Host)

        // Add target to shadow1
        const targetElement = document.createElement('div')
        targetElement.id = 'complex-target'
        shadow1Root.appendChild(targetElement)

        // Search from shadow2
        const fromElement = document.createElement('div')
        shadow2Root.appendChild(fromElement)

        const result = findElementInShadowRoots('complex-target', fromElement)
        assert.equal(result, targetElement)
      })

      it('returns null for invalid ID characters', () => {
        const element = document.createElement('div')
        element.id = 'valid-id'
        container.appendChild(element)

        const fromElement = document.createElement('div')
        container.appendChild(fromElement)

        // Test with empty string
        const result1 = findElementInShadowRoots('', fromElement)
        assert.isNull(result1)

        // Test with whitespace
        const result2 = findElementInShadowRoots('   ', fromElement)
        assert.isNull(result2)
      })
    })
  })
})
