import {test, expect} from '../../support/fixtures'
import {ProjectFactory} from '../../factories/project'
import {seed} from '../../support/seed'
import {TaskFactory} from '../../factories/task'
import {BucketFactory} from '../../factories/bucket'
import {updateUserSettings} from '../../support/updateUserSettings'
import {createDefaultViews} from '../project/prepareProjects'
import type {APIRequestContext} from '@playwright/test'

async function seedTasks(apiContext: APIRequestContext, numberOfTasks = 50, startDueDate = new Date()) {
	const project = (await ProjectFactory.create())[0]
	const views = await createDefaultViews(project.id)
	await BucketFactory.create(1, {
		project_view_id: views[3].id,
	})
	const tasks = []
	let dueDate = startDueDate
	for (let i = 0; i < numberOfTasks; i++) {
		const now = new Date()
		dueDate = new Date(new Date(dueDate).setDate(dueDate.getDate() + 2))
		tasks.push({
			id: i + 1,
			project_id: project.id,
			done: false,
			created_by_id: 1,
			title: 'Test Task ' + i,
			index: i + 1,
			due_date: dueDate.toISOString(),
			created: now.toISOString(),
			updated: now.toISOString(),
		})
	}
	await TaskFactory.seed(TaskFactory.table, tasks)
	return {tasks, project}
}

test.describe('Home Page Task Overview', () => {
	test('Should show tasks with a near due date first on the home page overview', async ({authenticatedPage: page, apiContext}) => {
		const taskCount = 50
		const {tasks} = await seedTasks(apiContext, taskCount)

		await page.goto('/')
		const taskElements = await page.locator('[data-cy="showTasks"] .card .task').all()
		for (let index = 0; index < taskElements.length; index++) {
			const taskText = await taskElements[index].innerText()
			expect(taskText).toContain(tasks[index].title)
		}
	})

	test('Should show overdue tasks first, then show other tasks', async ({authenticatedPage: page, apiContext}) => {
		const now = new Date()
		const oldDate = new Date(new Date(now).setDate(now.getDate() - 14))
		const taskCount = 50
		const {tasks} = await seedTasks(apiContext, taskCount, oldDate)

		await page.goto('/')
		const taskElements = await page.locator('[data-cy="showTasks"] .card .task').all()
		for (let index = 0; index < taskElements.length; index++) {
			const taskText = await taskElements[index].innerText()
			expect(taskText).toContain(tasks[index].title)
		}
	})

	test('Should show a new task with a very soon due date at the top', async ({authenticatedPage: page, apiContext}) => {
		const {tasks, project} = await seedTasks(apiContext, 49)
		const newTaskTitle = 'New Task'

		await page.goto('/')
		await page.waitForLoadState('networkidle')

		await TaskFactory.create(1, {
			id: 999,
			title: newTaskTitle,
			project_id: project.id,
			due_date: new Date().toISOString(),
		}, false)

		await page.goto(`/projects/${project.id}/1`)
		await page.waitForLoadState('networkidle')
		// Wait for the tasks list to load and contain the new task
		await expect(page.locator('.tasks')).toContainText(newTaskTitle)
		await page.goto('/')
		await page.waitForLoadState('networkidle')
		await expect(page.locator('[data-cy="showTasks"] .card .task').first()).toContainText(newTaskTitle)
	})

	test('Should not show a new task without a date at the bottom when there are > 50 tasks', async ({authenticatedPage: page, apiContext}) => {
		// We're not using the api here to create the task in order to verify the flow
		const {tasks} = await seedTasks(apiContext, 100)
		const newTaskTitle = 'New Task'

		await page.goto('/')
		await page.waitForLoadState('networkidle')

		await page.goto(`/projects/${tasks[0].project_id}/1`)
		await page.waitForLoadState('networkidle')
		const taskResponsePromise = page.waitForResponse('**/api/v1/projects/*/tasks')
		await page.locator('.task-add textarea').fill(newTaskTitle)
		await page.locator('.task-add textarea').press('Enter')
		await taskResponsePromise
		await page.goto('/')
		await page.waitForLoadState('networkidle')
		await expect(page.locator('[data-cy="showTasks"]')).not.toContainText(newTaskTitle)
	})

	test('Should show a new task without a date at the bottom when there are < 50 tasks', async ({authenticatedPage: page, apiContext}) => {
		const {project} = await seedTasks(apiContext, 40)
		const newTaskTitle = 'New Task'
		await TaskFactory.create(1, {
			id: 999,
			title: newTaskTitle,
			project_id: project.id,
		}, false)

		await page.goto('/')
		await page.waitForLoadState('networkidle')
		await expect(page.locator('[data-cy="showTasks"]')).toContainText(newTaskTitle)
	})

	test('Should show a task without a due date added via default project at the bottom', async ({authenticatedPage: page, apiContext}) => {
		const {project} = await seedTasks(apiContext, 40)

		// Navigate first to get access to localStorage
		await page.goto('/')
		await page.waitForLoadState('networkidle')
		const token = await page.evaluate(() => localStorage.getItem('token'))

		await updateUserSettings(apiContext, token, {
			default_project_id: project.id,
			overdue_tasks_reminders_time: '9:00',
		})

		const newTaskTitle = 'New Task'
		// Reload page to apply the new settings
		await page.reload()

		// Wait for page to be fully loaded
		await page.waitForLoadState('networkidle')

		// Wait for the add task input to be visible and ready
		const addTaskInput = page.locator('.add-task-textarea')
		await expect(addTaskInput).toBeVisible()

		await addTaskInput.fill(newTaskTitle)

		// Wait for the task creation request to complete
		const createTaskPromise = page.waitForResponse(response =>
			response.url().includes('/projects/') &&
			response.url().includes('/tasks') &&
			response.request().method() === 'PUT',
		)
		await addTaskInput.press('Enter')
		await createTaskPromise

		// Wait for the task to appear in the list (no due date tasks appear at the bottom)
		await expect(page.locator('[data-cy="showTasks"] .card .task').last()).toContainText(newTaskTitle, {timeout: 10000})
	})

	test('Should show the cta buttons for new project when there are no tasks', async ({authenticatedPage: page}) => {
		await TaskFactory.truncate()

		await page.goto('/')

		await expect(page.locator('.home.app-content .content')).toContainText('Import your projects and tasks from other services into Vikunja:')
	})

	test('Should not show the cta buttons for new project when there are tasks', async ({authenticatedPage: page, apiContext}) => {
		await seedTasks(apiContext)

		await page.goto('/')

		await expect(page.locator('.home.app-content .content')).not.toContainText('You can create a new project for your new tasks:')
		await expect(page.locator('.home.app-content .content')).not.toContainText('Or import your projects and tasks from other services into Vikunja:')
	})
})
