import {renderHook} from '@testing-library/react'
import {describe, expect, it, vi, beforeEach, afterEach} from 'vitest'

import {useDeeplink} from './useDeeplink'

vi.mock('../../utils/parseUrl', () => ({
  parseUrl: vi.fn(),
}))

const {parseUrl} = await import('../../utils/parseUrl')

describe('useDeeplink', () => {
  const originalMinisParams = (window as any).minisParams

  beforeEach(() => {
    vi.clearAllMocks()
  })

  afterEach(() => {
    ;(window as any).minisParams = originalMinisParams
  })

  describe('Without initialUrl', () => {
    beforeEach(() => {
      ;(window as any).minisParams = {
        initialUrl: undefined,
        handle: 'test-mini',
      }
    })

    it('returns undefined values when initialUrl is not provided', () => {
      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: undefined,
        queryParams: undefined,
        hash: undefined,
      })
      expect(parseUrl).not.toHaveBeenCalled()
    })
  })

  describe('With initialUrl', () => {
    beforeEach(() => {
      ;(window as any).minisParams = {
        initialUrl:
          'https://shop.app/mini/test-mini/products?category=clothing',
        handle: 'test-mini',
      }
    })

    it('parses URL and strips mini handle prefix from pathname', () => {
      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/products',
        query: {category: 'clothing'},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(parseUrl).toHaveBeenCalledWith(
        'https://shop.app/mini/test-mini/products?category=clothing'
      )
      expect(result.current).toEqual({
        path: '/products',
        queryParams: {category: 'clothing'},
        hash: '',
      })
    })

    it('returns pathname as-is when it does not contain mini handle prefix', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/some-other-path',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/some-other-path',
        query: {},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/some-other-path',
        queryParams: {},
        hash: '',
      })
    })

    it('handles URL with multiple query parameters', () => {
      ;(window as any).minisParams = {
        initialUrl:
          'https://shop.app/mini/test-mini/search?q=shoes&page=2&sort=price',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/search',
        query: {q: 'shoes', page: '2', sort: 'price'},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/search',
        queryParams: {q: 'shoes', page: '2', sort: 'price'},
        hash: '',
      })
    })

    it('handles URL with hash', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/page#section-2',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/page',
        query: {},
        hash: '#section-2',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/page',
        queryParams: {},
        hash: '#section-2',
      })
    })

    it('handles URL with both query params and hash', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/products?filter=sale#top',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/products',
        query: {filter: 'sale'},
        hash: '#top',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/products',
        queryParams: {filter: 'sale'},
        hash: '#top',
      })
    })

    it('handles root path after stripping prefix', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini',
        query: {},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '',
        queryParams: {},
        hash: '',
      })
    })

    it('handles root path with trailing slash', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/',
        query: {},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/',
        queryParams: {},
        hash: '',
      })
    })

    it('handles nested paths', () => {
      ;(window as any).minisParams = {
        initialUrl:
          'https://shop.app/mini/test-mini/category/shoes/product/123',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/category/shoes/product/123',
        query: {},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/category/shoes/product/123',
        queryParams: {},
        hash: '',
      })
    })

    it('handles different mini handle', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/another-mini/dashboard',
        handle: 'another-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/another-mini/dashboard',
        query: {},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/dashboard',
        queryParams: {},
        hash: '',
      })
    })
  })

  describe('Memoization', () => {
    it('returns same reference when dependencies do not change', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/products',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/products',
        query: {},
        hash: '',
      } as any)

      const {result, rerender} = renderHook(() => useDeeplink())
      const firstResult = result.current

      rerender()

      expect(result.current).toBe(firstResult)
      expect(parseUrl).toHaveBeenCalledTimes(1)
    })

    it('recomputes when initialUrl changes', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/products',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/products',
        query: {},
        hash: '',
      } as any)

      const {result, rerender} = renderHook(() => useDeeplink())
      const firstResult = result.current

      // Change initialUrl
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/cart',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/cart',
        query: {},
        hash: '',
      } as any)

      rerender()

      expect(result.current).not.toBe(firstResult)
      expect(result.current.path).toBe('/cart')
      expect(parseUrl).toHaveBeenCalledTimes(2)
    })

    it('recomputes when handle changes', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/products',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/products',
        query: {},
        hash: '',
      } as any)

      const {result, rerender} = renderHook(() => useDeeplink())
      const firstResult = result.current

      // Change handle
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/products',
        handle: 'different-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/products',
        query: {},
        hash: '',
      } as any)

      rerender()

      expect(result.current).not.toBe(firstResult)
      expect(parseUrl).toHaveBeenCalledTimes(2)
    })
  })

  describe('Edge Cases', () => {
    it('handles empty initialUrl string', () => {
      ;(window as any).minisParams = {
        initialUrl: '',
        handle: 'test-mini',
      }

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: undefined,
        queryParams: undefined,
        hash: undefined,
      })
      expect(parseUrl).not.toHaveBeenCalled()
    })

    it('handles null initialUrl', () => {
      ;(window as any).minisParams = {
        initialUrl: null,
        handle: 'test-mini',
      }

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: undefined,
        queryParams: undefined,
        hash: undefined,
      })
      expect(parseUrl).not.toHaveBeenCalled()
    })

    it('handles query params with undefined values', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini/search?q=&page=1',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/search',
        query: {q: undefined, page: '1'},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/search',
        queryParams: {q: undefined, page: '1'},
        hash: '',
      })
    })

    it('handles pathname with special characters', () => {
      ;(window as any).minisParams = {
        initialUrl:
          'https://shop.app/mini/test-mini/search?q=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini/search',
        query: {q: 'S�kao'},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '/search',
        queryParams: {q: 'S�kao'},
        hash: '',
      })
    })

    it('handles case where pathname is just the prefix', () => {
      ;(window as any).minisParams = {
        initialUrl: 'https://shop.app/mini/test-mini',
        handle: 'test-mini',
      }

      vi.mocked(parseUrl).mockReturnValue({
        pathname: '/mini/test-mini',
        query: {},
        hash: '',
      } as any)

      const {result} = renderHook(() => useDeeplink())

      expect(result.current).toEqual({
        path: '',
        queryParams: {},
        hash: '',
      })
    })
  })
})
