import { test, expect } from "#tests/e2e/fixtures/processing"

const MOCK_SEGMENTS = [
	{ start_ms: 5000, end_ms: 8000 },
	{ start_ms: 15000, end_ms: 19000 },
	{ start_ms: 32000, end_ms: 35000 },
	{ start_ms: 45000, end_ms: 50000 },
]
const MOCK_DURATION_MS = 60000

function buildNotification(
	jobId: string,
	overrides: Record<string, unknown> = {},
) {
	return {
		event: "task_update",
		notification_id: null,
		job_id: jobId,
		project_id: null,
		job_type: "SILENCE_DETECT",
		status: "RUNNING",
		progress_pct: 0,
		message: null,
		title: null,
		created_at: new Date().toISOString(),
		is_read: false,
		...overrides,
	}
}

test.describe("Processing Step (Integration)", () => {
	test.describe("Initial State", () => {
		test("should display the processing step with progress and status label", async ({
			processingPage,
		}) => {
			const { processingStep } = processingPage

			await expect(processingStep).toBeVisible()
			await expect(processingStep.getByText("0%")).toBeVisible()
			await expect(processingStep.getByText("АНАЛИЗ")).toBeVisible()
		})

		test("should display the default status message", async ({
			processingPage,
		}) => {
			const { processingStep } = processingPage

			await expect(
				processingStep.getByText("Подождите, идёт обработка..."),
			).toBeVisible()
		})

		test("should display the info card about server processing", async ({
			processingPage,
		}) => {
			const { processingStep } = processingPage

			await expect(
				processingStep.getByText(
					"Обработка выполняется на сервере. Вы можете покинуть страницу — прогресс сохранится.",
				),
			).toBeVisible()
		})

		test("should display the cancel button", async ({
			processingPage,
		}) => {
			const { processingStep } = processingPage

			const cancelButton = processingStep.getByRole("button", {
				name: "Отменить обработку",
			})
			await expect(cancelButton).toBeVisible()
			await expect(cancelButton).toBeEnabled()
		})
	})

	test.describe("Progress Updates", () => {
		test("should display updated progress percentage from notifications", async ({
			processingPage,
		}) => {
			const { page, processingStep, jobId } = processingPage

			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					progress_pct: 45,
					message: "Анализируем аудио...",
				}),
			)

			await expect(processingStep.getByText("45%")).toBeVisible()
			await expect(
				processingStep.getByText("Анализируем аудио..."),
			).toBeVisible()
			await expect(processingStep.getByText("АНАЛИЗ")).toBeVisible()
		})

		test("should update progress when notification changes", async ({
			processingPage,
		}) => {
			const { page, processingStep, jobId } = processingPage

			// First update: 25%
			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					progress_pct: 25,
					message: "Обработка...",
				}),
			)
			await expect(processingStep.getByText("25%")).toBeVisible()

			// Second update: 75%
			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					progress_pct: 75,
					message: "Почти готово...",
				}),
			)
			await expect(processingStep.getByText("75%")).toBeVisible()
			await expect(
				processingStep.getByText("Почти готово..."),
			).toBeVisible()
		})
	})

	test.describe("Auto-Advance on Completion", () => {
		test("should auto-advance to fragments step when task status returns DONE", async ({
			processingPage,
		}) => {
			const { page } = processingPage

			// Replace the route to return DONE
			await page.unrouteAll({ behavior: "ignoreErrors" })
			await page.route("**/api/tasks/status/**", async (route) => {
				await route.fulfill({
					status: 200,
					contentType: "application/json",
					body: JSON.stringify({
						status: "DONE",
						progress_pct: 100,
						output_data: {
							silent_segments: MOCK_SEGMENTS,
							duration_ms: MOCK_DURATION_MS,
						},
					}),
				})
			})

			// Wait for auto-advance (polls every 2s)
			await expect(
				page.locator("[data-testid='FragmentsStep']"),
			).toBeVisible({ timeout: 10_000 })

			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).not.toBeVisible()
		})

		test("should auto-advance when notification reports DONE", async ({
			processingPage,
		}) => {
			const { page, jobId } = processingPage

			// Dispatch DONE notification (auto-advance also checks notifications)
			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					status: "DONE",
					progress_pct: 100,
				}),
			)

			// The WizardContext auto-advance also needs the polling to confirm,
			// so update the route too
			await page.unrouteAll({ behavior: "ignoreErrors" })
			await page.route("**/api/tasks/status/**", async (route) => {
				await route.fulfill({
					status: 200,
					contentType: "application/json",
					body: JSON.stringify({
						status: "DONE",
						progress_pct: 100,
						output_data: {
							silent_segments: MOCK_SEGMENTS,
							duration_ms: MOCK_DURATION_MS,
						},
					}),
				})
			})

			await expect(
				page.locator("[data-testid='FragmentsStep']"),
			).toBeVisible({ timeout: 10_000 })
		})
	})

	test.describe("Failure State", () => {
		test("should display error state when notification status is FAILED", async ({
			processingPage,
		}) => {
			const { page, processingStep, jobId } = processingPage

			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					status: "FAILED",
					message: "Файл повреждён",
				}),
			)

			await expect(processingStep.getByText("ОШИБКА")).toBeVisible()
			await expect(
				processingStep.getByText("Файл повреждён"),
			).toBeVisible()

			// Button should change from "Отменить обработку" to "Назад"
			await expect(
				processingStep.getByRole("button", { name: "Назад" }),
			).toBeVisible()
			await expect(
				processingStep.getByRole("button", {
					name: "Отменить обработку",
				}),
			).not.toBeVisible()
		})

		test("should show default error message when FAILED notification has no message", async ({
			processingPage,
		}) => {
			const { page, processingStep, jobId } = processingPage

			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					status: "FAILED",
					message: null,
				}),
			)

			await expect(
				processingStep.getByText("Произошла ошибка при обработке"),
			).toBeVisible()
		})

		test("should navigate back to silence settings when clicking back in error state", async ({
			processingPage,
		}) => {
			const { page, processingStep, jobId } = processingPage

			await page.evaluate(
				(payload) => {
					;(window as any).__REDUX_STORE__?.dispatch({
						type: "notifications/addNotification",
						payload,
					})
				},
				buildNotification(jobId, {
					status: "FAILED",
					message: "Ошибка обработки",
				}),
			)

			await processingStep
				.getByRole("button", { name: "Назад" })
				.click()

			await expect(
				page.locator("[data-testid='SilenceSettingsStep']"),
			).toBeVisible({ timeout: 10_000 })
			await expect(processingStep).not.toBeVisible()
		})
	})

	test.describe("Cancel", () => {
		test("should navigate back to silence settings when cancel button is clicked", async ({
			processingPage,
		}) => {
			const { page, processingStep } = processingPage

			await processingStep
				.getByRole("button", { name: "Отменить обработку" })
				.click()

			await expect(
				page.locator("[data-testid='SilenceSettingsStep']"),
			).toBeVisible({ timeout: 10_000 })
			await expect(processingStep).not.toBeVisible()
		})

		test("should start a new job when clicking Далее again after cancel", async ({
			processingPage,
		}) => {
			const { page, processingStep } = processingPage

			// Cancel
			await processingStep
				.getByRole("button", { name: "Отменить обработку" })
				.click()

			const silenceStep = page.locator(
				"[data-testid='SilenceSettingsStep']",
			)
			await silenceStep.waitFor({ timeout: 10_000 })

			// Capture new request
			let newPostMade = false
			page.on("request", (req) => {
				if (
					req.url().includes("/api/tasks/silence-detect/") &&
					req.method() === "POST"
				) {
					newPostMade = true
				}
			})

			// Click "Далее" again
			await silenceStep
				.getByRole("button", { name: "Далее" })
				.click()

			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).toBeVisible({ timeout: 10_000 })

			expect(newPostMade).toBe(true)
		})
	})

	test.describe("State Persistence", () => {
		test("should restore processing step after page reload", async ({
			processingPage,
		}) => {
			const { page } = processingPage

			// Wait for debounced save
			await page.waitForTimeout(2500)

			// Reload — route intercepts are lost, re-add before reload completes
			await page.reload()
			await page.route("**/api/tasks/status/**", async (route) => {
				await route.fulfill({
					status: 200,
					contentType: "application/json",
					body: JSON.stringify({
						status: "RUNNING",
						progress_pct: 0,
						output_data: null,
					}),
				})
			})

			await page
				.locator("[data-testid='ProjectWizard']")
				.waitFor({ timeout: 10_000 })

			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).toBeVisible({ timeout: 10_000 })
		})

		test("should resume polling and auto-advance after page reload", async ({
			processingPage,
		}) => {
			const { page } = processingPage

			// Wait for debounced save
			await page.waitForTimeout(2500)

			// Reload and set up route to return DONE
			await page.reload()
			await page.route("**/api/tasks/status/**", async (route) => {
				await route.fulfill({
					status: 200,
					contentType: "application/json",
					body: JSON.stringify({
						status: "DONE",
						progress_pct: 100,
						output_data: {
							silent_segments: MOCK_SEGMENTS,
							duration_ms: MOCK_DURATION_MS,
						},
					}),
				})
			})

			await page
				.locator("[data-testid='ProjectWizard']")
				.waitFor({ timeout: 10_000 })

			// Should auto-advance to fragments after polling picks up DONE
			await expect(
				page.locator("[data-testid='FragmentsStep']"),
			).toBeVisible({ timeout: 15_000 })
		})
	})
})
