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

interface CreateProjectRequestBody {
	description?: string
	language?: string
	name?: string
}

function requirePostBody(
	postBody: CreateProjectRequestBody | null,
): CreateProjectRequestBody {
	if (!postBody) {
		throw new Error("Expected create project request body to be captured")
	}

	return postBody
}

// Note: ReactModal sets aria-modal="true" on the dialog, which makes
// Playwright's getByRole() unable to find elements inside or outside the modal.
// All modal content is accessed via CSS locators scoped through `modal`.

test.describe("Create Project Modal", () => {
	test.describe("Rendering & UI", () => {
		test("should display create project modal with all fields", async ({
			projectsPage,
		}) => {
			const { modal } = projectsPage
			await projectsPage.openCreateModal()

			await expect(modal.locator("h2")).toHaveText("Создать проект")
			await expect(modal.locator("p").first()).toHaveText(
				"Заполните основные поля проекта",
			)
			await expect(modal.locator("#project_name")).toHaveValue("")
			await expect(modal.locator("#project_description")).toHaveValue("")
			await expect(modal.locator("button", { hasText: "Отмена" })).toBeVisible()
			await expect(
				modal.locator("button", { hasText: "Создать" }),
			).toBeVisible()
		})

		test("should show default language as Авто", async ({ projectsPage }) => {
			const { modal } = projectsPage
			await projectsPage.openCreateModal()

			const selectTrigger = modal.locator("button").filter({ hasText: "Авто" })
			await expect(selectTrigger).toBeVisible()
		})
	})

	test.describe("Happy Path", () => {
		test("should create project with name only", async ({ projectsPage }) => {
			const { page, modal } = projectsPage

			let postBody: CreateProjectRequestBody | null = null
			await projectsPage.mockCreateSuccess({ name: "Мой проект" })

			page.on("request", (req) => {
				if (req.url().includes("/api/projects/") && req.method() === "POST") {
					postBody = req.postDataJSON()
				}
			})

			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Мой проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			// Modal should close
			await expect(modal).toBeHidden()

			const requestBody = requirePostBody(postBody)
			expect(requestBody.name).toBe("Мой проект")
			expect(requestBody.language).toBe("auto")
		})

		test("should create project with name and description", async ({
			projectsPage,
		}) => {
			const { page, modal } = projectsPage

			let postBody: CreateProjectRequestBody | null = null
			await projectsPage.mockCreateSuccess({
				name: "Мой проект",
				description: "Описание проекта",
			})

			page.on("request", (req) => {
				if (req.url().includes("/api/projects/") && req.method() === "POST") {
					postBody = req.postDataJSON()
				}
			})

			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Мой проект")
			await modal.locator("#project_description").fill("Описание проекта")
			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(modal).toBeHidden()

			const requestBody = requirePostBody(postBody)
			expect(requestBody.description).toBe("Описание проекта")
		})

		test("should create project with different language", async ({
			projectsPage,
		}) => {
			const { page, modal } = projectsPage

			let postBody: CreateProjectRequestBody | null = null
			await projectsPage.mockCreateSuccess({
				name: "Мой проект",
				language: "ru",
			})

			page.on("request", (req) => {
				if (req.url().includes("/api/projects/") && req.method() === "POST") {
					postBody = req.postDataJSON()
				}
			})

			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Мой проект")

			// Open language select and pick Russian
			await modal.locator("button").filter({ hasText: "Авто" }).click()
			await page.locator("[role=option]", { hasText: "Русский" }).click()

			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(modal).toBeHidden()

			const requestBody = requirePostBody(postBody)
			expect(requestBody.language).toBe("ru")
		})

		test("should refresh projects list after creation", async ({
			projectsPage,
		}) => {
			const { page, modal } = projectsPage

			// Verify empty state
			await expect(page.getByText("У вас пока нет проектов")).toBeVisible()

			await projectsPage.mockCreateSuccess({ name: "Новый проект" })
			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Новый проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			// Modal closes and project appears in list
			await expect(modal).toBeHidden()
			await expect(page.getByText("У вас пока нет проектов")).toBeHidden()
			await expect(page.getByText("Новый проект")).toBeVisible()
		})
	})

	test.describe("Validation", () => {
		test("should show validation error for empty name", async ({
			projectsPage,
		}) => {
			const { page, modal } = projectsPage
			let postFired = false

			page.on("request", (req) => {
				if (req.url().includes("/api/projects/") && req.method() === "POST") {
					postFired = true
				}
			})

			await projectsPage.openCreateModal()
			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(modal.getByText("Введите название проекта")).toBeVisible()
			expect(postFired).toBe(false)

			// Modal stays open
			await expect(modal).toBeVisible()
		})

		test("should show validation error for whitespace-only name", async ({
			projectsPage,
		}) => {
			const { modal } = projectsPage

			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("   ")
			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(modal.getByText("Введите название проекта")).toBeVisible()
		})

		test("should clear validation error after correcting name", async ({
			projectsPage,
		}) => {
			const { modal } = projectsPage
			await projectsPage.mockCreateSuccess({ name: "Проект" })

			await projectsPage.openCreateModal()

			// Trigger validation error
			await modal.locator("button", { hasText: "Создать" }).click()
			await expect(modal.getByText("Введите название проекта")).toBeVisible()

			// Fix and resubmit
			await modal.locator("#project_name").fill("Проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(modal).toBeHidden()
		})
	})

	test.describe("Error States", () => {
		test("should keep modal open on server error (500)", async ({
			projectsPage,
		}) => {
			const { page, modal } = projectsPage
			const consoleErrors: string[] = []

			page.on("console", (msg) => {
				if (msg.type() === "error") {
					consoleErrors.push(msg.text())
				}
			})

			await projectsPage.mockCreateError(500)
			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			// Wait for error to be processed
			await page.waitForTimeout(1000)

			// Modal stays open, buttons re-enable
			await expect(modal).toBeVisible()
			await expect(
				modal.locator("button", { hasText: "Создать" }),
			).toBeEnabled()
			await expect(modal.locator("button", { hasText: "Отмена" })).toBeEnabled()

			expect(
				consoleErrors.some((e) => e.includes("Create project failed")),
			).toBe(true)
		})

		test("should keep modal open on network error", async ({
			projectsPage,
		}) => {
			const { page, modal } = projectsPage

			await projectsPage.mockCreateNetworkError()
			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			await page.waitForTimeout(1000)

			await expect(modal).toBeVisible()
			await expect(
				modal.locator("button", { hasText: "Создать" }),
			).toBeEnabled()
			await expect(modal.locator("button", { hasText: "Отмена" })).toBeEnabled()
		})

		test("should allow retry after failure", async ({ projectsPage }) => {
			const { page, modal } = projectsPage

			// First attempt: 500 error
			await projectsPage.mockCreateError(500)
			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			await page.waitForTimeout(1000)
			await expect(
				modal.locator("button", { hasText: "Создать" }),
			).toBeEnabled()

			// Second attempt: success (re-mock the route)
			await projectsPage.mockCreateSuccess({ name: "Проект" })
			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(modal).toBeHidden()
		})
	})

	test.describe("Form Behavior", () => {
		test("should reset form when modal is closed and reopened", async ({
			projectsPage,
		}) => {
			const { modal } = projectsPage

			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Черновик")
			await modal.locator("#project_description").fill("Описание черновика")

			// Close with Cancel
			await modal.locator("button", { hasText: "Отмена" }).click()
			await expect(modal).toBeHidden()

			// Reopen
			await projectsPage.openCreateModal()
			await expect(modal.locator("#project_name")).toHaveValue("")
			await expect(modal.locator("#project_description")).toHaveValue("")
			await expect(
				modal.locator("button").filter({ hasText: "Авто" }),
			).toBeVisible()
		})

		test("should disable buttons while request is pending", async ({
			projectsPage,
		}) => {
			const { modal } = projectsPage

			await projectsPage.mockCreateDelayed(2000)
			await projectsPage.openCreateModal()
			await modal.locator("#project_name").fill("Проект")
			await modal.locator("button", { hasText: "Создать" }).click()

			await expect(
				modal.locator("button", { hasText: "Создать" }),
			).toBeDisabled()
			await expect(
				modal.locator("button", { hasText: "Отмена" }),
			).toBeDisabled()
		})
	})
})
