
import { newE2EPage } from '@stencil/core/testing'
import faker from 'faker'
import { getServiceConfigByType } from '../../shared/services'

function randomNumber(min, max, width = 0) {
    let n = faker.random.number({ min, max }) + ''
    return n.length >= width ? n : new Array(width - n.length + 1).join('0') + n
}

describe('gd-user-dashboard-list-item', () => {
    let page, component, historyItem

    beforeEach(async () => {
        page = await newE2EPage()

        await page.setContent(`
            <gd-user-dashboard-list-item></gd-user-dashboard-list-item>
        `)

        component = await page.find('gd-user-dashboard-list-item')

        // create a fake history item
        historyItem = {
            url: 'https://www.google.com',
            label: faker.lorem.words(5),
            serviceType: faker.helpers.randomize(['data', 'doc']),
            tags: faker.lorem.words(5).split(' '),
            favorite: faker.random.boolean(),
            application: "GES DISC Website",
            uid: "jdoe",
            created: `2020-${randomNumber(1, 12, 2)}-${randomNumber(1, 28, 2)}T${randomNumber(1, 20, 2)}:${randomNumber(1, 59, 2)}:19.614Z`,
            id: "foo",
        }

        // pass the fake history item to the component
        await page.$eval('gd-user-dashboard-list-item', (el: any, historyItem) => {
            el.item = historyItem
        }, historyItem)

        await page.waitForChanges()
    })

    it('renders', async () => {
        const label = await page.find('gd-user-dashboard-list-item >>> .label')

        expect(component).toHaveClass('hydrated')
        expect(await label.textContent).toBe(historyItem.label)     // ensure label is displayed
    })

    it('should display url if no label is present', async () => {
        const testHistoryItem = { ...historyItem }

        delete testHistoryItem.label
        await page.$eval('gd-user-dashboard-list-item', (el: any, historyItem) => el.item = historyItem, testHistoryItem)
        await page.waitForChanges()

        const label = await page.find('gd-user-dashboard-list-item >>> .label')
        
        expect(await label.textContent).toBe(historyItem.url)
    })

    it('should not trigger labelClick event by default', async () => {
        const eventSpy = await component.spyOnEvent('labelClick')

        const label = await page.find('gd-user-dashboard-list-item >>> .label')

        await label.click()
        await page.waitForChanges()

        expect(eventSpy).not.toHaveReceivedEvent()
    })

    it('should trigger labelClick event when url is a JSON object', async () => {
        const eventSpy = await component.spyOnEvent('labelClick')
        const url = '{"foo":"bar"}'
        const testHistoryItem = {
            ...historyItem,
            url,
        }

        // update url in history item to use the JSON object
        await page.$eval('gd-user-dashboard-list-item', (el: any, historyItem) => el.item = historyItem, testHistoryItem)

        await page.waitForChanges()

        const label = await page.find('gd-user-dashboard-list-item >>> .label')

        await label.click()
        await page.waitForChanges()

        expect(eventSpy).toHaveReceivedEvent()
        expect(eventSpy).toHaveReceivedEventDetail(testHistoryItem)
    })

    it('should trigger labelClick event when followUrl is false', async () => {
        const eventSpy = await component.spyOnEvent('labelClick')

        await page.$eval('gd-user-dashboard-list-item', (el: any) => el.followUrl = false)
        await page.waitForChanges()

        const label = await page.find('gd-user-dashboard-list-item >>> .label')

        await label.click()
        await page.waitForChanges()

        expect(eventSpy).toHaveReceivedEvent()
        expect(eventSpy).toHaveReceivedEventDetail(historyItem)
    })

    it('properly formats the date', async () => {
        const timestamp = '2020-11-25T15:14:25.173Z'
        const formattedTimestamp = '11-25-2020 10:14:25'
        const testHistoryItem = {
            ...historyItem,
            created: timestamp,
        }

        // change the date so we can be sure it renders correctly
        await page.$eval('gd-user-dashboard-list-item', (el: any, historyItem) => {
            el.item = historyItem
        }, testHistoryItem)

        await page.waitForChanges()

        const dateEl = await page.find('gd-user-dashboard-list-item >>> .date')
        
        expect(await dateEl.textContent).toBe(formattedTimestamp)
    })

    // create a testing table to ensure the given serviceType renders a different icon
    // the icon itself doesn't really matter, just want to make sure it changes, so grab the right icon from services
    test.each`
        serviceType | icon
        ${'data'}   | ${getServiceConfigByType('data').icon}
        ${'doc'}    | ${getServiceConfigByType('doc').icon}
        ${'foo'}    | ${getServiceConfigByType('doc').icon}
    `('correctly renders icon when serviceType changes (using $serviceType)', async ({ serviceType, icon}) => {
        const testHistoryItem = {
            ...historyItem,
            serviceType: serviceType,
        }

        // change the service type so we can be sure it renders the icon correctly
        await page.$eval('gd-user-dashboard-list-item', (el: any, historyItem) => {
            el.item = historyItem
        }, testHistoryItem)
        
        await page.waitForChanges()

        // get the icon element and make sure it's icon prop has changed to match the service type
        const iconEl = await page.find('gd-user-dashboard-list-item >>> bs-icon')
        expect(await iconEl.getProperty('icon')).toBe(`fab ${icon}`)
    })

    it('should trigger updateItem event with favorite toggled when favorite button is clicked', async () => {
        const eventSpy = await component.spyOnEvent('updateItem')
        
        const favoriteBtn = await page.find('gd-user-dashboard-list-item >>> .favorite')

        await favoriteBtn.click()
        await page.waitForChanges()

        expect(eventSpy).toHaveReceivedEvent()
        expect(eventSpy).toHaveReceivedEventDetail({
            ...historyItem,
            favorite: !historyItem.favorite,
        })
    })

    it('should trigger deleteItem event when delete button is clicked and confirmed', async () => {
        const eventSpy = await component.spyOnEvent('deleteItem')
        
        const btn = await page.find('gd-user-dashboard-list-item >>> .delete')

        page.on('dialog', (dialog) => {
            dialog.accept()
        })

        await btn.click()
        await page.waitForChanges()

        expect(eventSpy).toHaveReceivedEvent()
        expect(eventSpy).toHaveReceivedEventDetail(historyItem)
    })
})
