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

test.describe("Silence Settings Step (Integration)", () => {
	test.describe("Initial State", () => {
		test("should display the title and description", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			await expect(
				silenceStep.getByText("Параметры обнаружения тишины"),
			).toBeVisible()
			await expect(
				silenceStep.getByText(
					"Настройте параметры для автоматического обнаружения тихих участков в видео",
				),
			).toBeVisible()
		})

		test("should show all three sliders with default values", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			// Min silence duration slider: default 200 ms
			const durationSlider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Мин. длительность тишины" })
			await expect(durationSlider).toBeVisible()
			await expect(durationSlider.getByText("200 мс")).toBeVisible()
			await expect(
				durationSlider.locator("input[type='range']"),
			).toHaveValue("200")

			// Silence threshold slider: default 16 dB
			const thresholdSlider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Порог тишины" })
			await expect(thresholdSlider).toBeVisible()
			await expect(thresholdSlider.getByText("16 дБ")).toBeVisible()
			await expect(
				thresholdSlider.locator("input[type='range']"),
			).toHaveValue("16")

			// Padding slider: default 100 ms
			const paddingSlider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Отступ" })
			await expect(paddingSlider).toBeVisible()
			await expect(paddingSlider.getByText("100 мс")).toBeVisible()
			await expect(
				paddingSlider.locator("input[type='range']"),
			).toHaveValue("100")
		})

		test("should display help texts for each slider", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			await expect(
				silenceStep.getByText(
					"Минимальная длительность тихого участка для обнаружения",
				),
			).toBeVisible()
			await expect(
				silenceStep.getByText(
					"Уровень громкости ниже которого звук считается тишиной",
				),
			).toBeVisible()
			await expect(
				silenceStep.getByText(
					"Дополнительный отступ по краям тихих участков",
				),
			).toBeVisible()
		})

		test("should show back and forward navigation buttons", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			const backButton = silenceStep.getByRole("button", {
				name: "Назад",
			})
			const forwardButton = silenceStep.getByRole("button", {
				name: "Далее",
			})

			await expect(backButton).toBeVisible()
			await expect(backButton).toBeEnabled()
			await expect(forwardButton).toBeVisible()
			await expect(forwardButton).toBeEnabled()
		})
	})

	test.describe("Slider Interactions", () => {
		test("should update min silence duration slider value when changed", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			const slider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Мин. длительность тишины" })
			const input = slider.locator("input[type='range']")

			await input.fill("500")

			await expect(input).toHaveValue("500")
			await expect(slider.getByText("500 мс")).toBeVisible()
		})

		test("should update silence threshold slider value when changed", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			const slider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Порог тишины" })
			const input = slider.locator("input[type='range']")

			await input.fill("24")

			await expect(input).toHaveValue("24")
			await expect(slider.getByText("24 дБ")).toBeVisible()
		})

		test("should update padding slider value when changed", async ({
			silencePage,
		}) => {
			const { silenceStep } = silencePage

			const slider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Отступ" })
			const input = slider.locator("input[type='range']")

			await input.fill("250")

			await expect(input).toHaveValue("250")
			await expect(slider.getByText("250 мс")).toBeVisible()
		})
	})

	test.describe("Successful Submission", () => {
		test("should submit with default values and navigate to Processing step", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

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

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

		test("should send correct request body with default values to the API", async ({
			silencePage,
		}) => {
			const { page, projectId, silenceStep } = silencePage

			let postBody: Record<string, unknown> | null = null
			page.on("request", (req) => {
				if (
					req.url().includes("/api/tasks/silence-detect/") &&
					req.method() === "POST"
				) {
					postBody = req.postDataJSON()
				}
			})

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

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

			expect(postBody).not.toBeNull()
			expect(postBody!.project_id).toBe(projectId)
			expect(postBody!.min_silence_duration_ms).toBe(200)
			expect(postBody!.silence_threshold_db).toBe(16)
			expect(postBody!.padding_ms).toBe(100)
			// file_key should be a non-empty string populated from the uploaded file
			expect(postBody!.file_key).toBeTruthy()
			expect(typeof postBody!.file_key).toBe("string")
		})

		test("should send correct request body with modified slider values", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

			// Modify all three sliders
			await silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Мин. длительность тишины" })
				.locator("input[type='range']")
				.fill("800")

			await silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Порог тишины" })
				.locator("input[type='range']")
				.fill("30")

			await silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Отступ" })
				.locator("input[type='range']")
				.fill("375")

			let postBody: Record<string, unknown> | null = null
			page.on("request", (req) => {
				if (
					req.url().includes("/api/tasks/silence-detect/") &&
					req.method() === "POST"
				) {
					postBody = req.postDataJSON()
				}
			})

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

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

			expect(postBody).not.toBeNull()
			expect(postBody!.min_silence_duration_ms).toBe(800)
			expect(postBody!.silence_threshold_db).toBe(30)
			expect(postBody!.padding_ms).toBe(375)
		})
	})

	test.describe("Navigation", () => {
		test("should navigate back to Verify step when back button is clicked", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

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

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

			// Silence Settings step should no longer be visible
			await expect(silenceStep).not.toBeVisible()
		})
	})

	test.describe("Error States", () => {
		test("should stay on silence settings step when API returns network error", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

			await page.route("**/api/tasks/silence-detect/**", (route) =>
				route.abort(),
			)
			await page.route("**/api/tasks/silence-detect/", (route) =>
				route.abort(),
			)

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

			// Should NOT navigate to Processing step
			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).not.toBeVisible({ timeout: 5_000 })

			// Should remain on Silence Settings step
			await expect(silenceStep).toBeVisible()
		})

		test("should stay on silence settings step when API returns 500", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

			await page.route("**/api/tasks/silence-detect/**", (route) =>
				route.fulfill({
					status: 500,
					contentType: "application/json",
					body: JSON.stringify({
						detail: "Internal Server Error",
					}),
				}),
			)
			await page.route("**/api/tasks/silence-detect/", (route) =>
				route.fulfill({
					status: 500,
					contentType: "application/json",
					body: JSON.stringify({
						detail: "Internal Server Error",
					}),
				}),
			)

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

			// Should NOT navigate to Processing step
			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).not.toBeVisible({ timeout: 5_000 })

			// Should remain on Silence Settings step
			await expect(silenceStep).toBeVisible()
		})

		test("should allow retrying after a network failure", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

			// First attempt: abort the request
			await page.route("**/api/tasks/silence-detect/**", (route) =>
				route.abort(),
			)
			await page.route("**/api/tasks/silence-detect/", (route) =>
				route.abort(),
			)

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

			// Should stay on silence settings
			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).not.toBeVisible({ timeout: 5_000 })
			await expect(silenceStep).toBeVisible()

			// Remove intercepts and retry
			await page.unrouteAll({ behavior: "ignoreErrors" })

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

			// Should succeed and navigate to Processing step
			await expect(
				page.locator("[data-testid='ProcessingStep']"),
			).toBeVisible({ timeout: 10_000 })
		})

		test("should show pending text and disable buttons while submission is in flight", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

			// Delay the API response to observe the pending state
			await page.route(
				"**/api/tasks/silence-detect/**",
				async (route) => {
					await new Promise((r) => setTimeout(r, 3000))
					await route.fulfill({
						status: 200,
						contentType: "application/json",
						body: JSON.stringify({ job_id: "fake-job-id" }),
					})
				},
			)
			await page.route(
				"**/api/tasks/silence-detect/",
				async (route) => {
					await new Promise((r) => setTimeout(r, 3000))
					await route.fulfill({
						status: 200,
						contentType: "application/json",
						body: JSON.stringify({ job_id: "fake-job-id" }),
					})
				},
			)

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

			// Submit button should show "Запуск..." and be disabled
			const submitButton = silenceStep.getByRole("button", {
				name: "Запуск...",
			})
			await expect(submitButton).toBeVisible({ timeout: 2_000 })
			await expect(submitButton).toBeDisabled()

			// Back button should also be disabled during pending state
			const backButton = silenceStep.getByRole("button", {
				name: "Назад",
			})
			await expect(backButton).toBeDisabled()
		})
	})

	test.describe("State Persistence", () => {
		test("should persist modified silence settings across page reloads", async ({
			silencePage,
		}) => {
			const { page, silenceStep } = silencePage

			// Change the min silence duration slider
			const durationSlider = silenceStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Мин. длительность тишины" })
			await durationSlider.locator("input[type='range']").fill("750")

			// Verify the value changed
			await expect(durationSlider.getByText("750 мс")).toBeVisible()

			// Wait for the debounced save to persist (1000ms debounce + network)
			await page.waitForTimeout(2500)

			// Reload the page
			await page.reload()
			await page.locator("[data-testid='ProjectWizard']").waitFor()

			// Should restore to the silence settings step with persisted value
			const restoredStep = page.locator(
				"[data-testid='SilenceSettingsStep']",
			)
			await expect(restoredStep).toBeVisible({ timeout: 10_000 })

			const restoredSlider = restoredStep
				.locator("[data-testid='Slider']")
				.filter({ hasText: "Мин. длительность тишины" })
			await expect(restoredSlider.getByText("750 мс")).toBeVisible({
				timeout: 5_000,
			})
			await expect(
				restoredSlider.locator("input[type='range']"),
			).toHaveValue("750")
		})
	})
})
