import XCTest

/// Integration tests for task operations against the real local backend.
///
/// Test Plan IDs: TASK-010, TASK-012, plus create/edit flows.
/// Data is seeded via API and cleaned up in tearDown.
final class TaskIntegrationTests: AuthenticatedUITestCase {
    override var needsAPISession: Bool { true }
    override var testCredentials: (username: String, password: String) { ("admin", "Test1234") }
    override var apiCredentials: (username: String, password: String) { ("admin", "Test1234") }

    // MARK: - Create Task

    func testTASK_CreateTaskAppearsInList() {
        // Seed a residence via API so task creation has a valid target
        let residence = cleaner.seedResidence()

        navigateToTasks()

        let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch
        let emptyState = app.otherElements[AccessibilityIdentifiers.Task.emptyStateView]
        let taskList = app.otherElements[AccessibilityIdentifiers.Task.tasksList]

        let loaded = addButton.waitForExistence(timeout: defaultTimeout)
            || emptyState.waitForExistence(timeout: 3)
            || taskList.waitForExistence(timeout: 3)
        XCTAssertTrue(loaded, "Tasks screen should load")

        if addButton.exists && addButton.isHittable {
            addButton.forceTap()
        } else {
            let emptyAddButton = app.buttons.containing(
                NSPredicate(format: "label CONTAINS[c] 'Add' OR label CONTAINS[c] 'Create'")
            ).firstMatch
            emptyAddButton.waitForExistenceOrFail(timeout: defaultTimeout)
            emptyAddButton.forceTap()
        }

        let titleField = app.textFields[AccessibilityIdentifiers.Task.titleField]
        titleField.waitForExistenceOrFail(timeout: defaultTimeout)
        let uniqueTitle = "IntTest Task \(Int(Date().timeIntervalSince1970))"
        titleField.forceTap()
        _ = app.keyboards.firstMatch.waitForExistence(timeout: 3)
        titleField.typeText(uniqueTitle)

        let saveButton = app.buttons[AccessibilityIdentifiers.Task.saveButton]
        let scrollContainer = app.scrollViews.firstMatch.exists ? app.scrollViews.firstMatch : app.collectionViews.firstMatch
        saveButton.scrollIntoView(in: scrollContainer)
        saveButton.forceTap()

        let newTask = app.staticTexts[uniqueTitle]
        XCTAssertTrue(
            newTask.waitForExistence(timeout: loginTimeout),
            "Newly created task should appear"
        )
    }

    // MARK: - TASK-010: Uncancel Task

    func testTASK010_UncancelTaskFlow() throws {
        // Seed a cancelled task via API
        let residence = cleaner.seedResidence()
        let cancelledTask = TestDataSeeder.createCancelledTask(token: session.token, residenceId: residence.id)
        cleaner.trackTask(cancelledTask.id)

        navigateToTasks()

        // Pull to refresh until the cancelled task is visible
        let taskText = app.staticTexts[cancelledTask.title]
        pullToRefreshUntilVisible(taskText)
        guard taskText.waitForExistence(timeout: defaultTimeout) else {
            throw XCTSkip("Cancelled task not visible in current view")
        }
        taskText.forceTap()

        // Look for an uncancel or reopen button
        let uncancelButton = app.buttons.containing(
            NSPredicate(format: "label CONTAINS[c] 'Uncancel' OR label CONTAINS[c] 'Reopen' OR label CONTAINS[c] 'Restore'")
        ).firstMatch

        if uncancelButton.waitForExistence(timeout: defaultTimeout) {
            uncancelButton.forceTap()

            let statusText = app.staticTexts.containing(
                NSPredicate(format: "label CONTAINS[c] 'Cancelled'")
            ).firstMatch
            XCTAssertFalse(statusText.exists, "Task should no longer show as cancelled after uncancel")
        }
    }

    // MARK: - TASK-010 (v2): Uncancel Task — Restores Cancelled Task to Active Lifecycle

    func test15_uncancelRestorescancelledTask() throws {
        // Seed a residence and a task, then cancel the task via API
        let residence = cleaner.seedResidence(name: "Uncancel Test Residence \(Int(Date().timeIntervalSince1970))")
        let task = cleaner.seedTask(residenceId: residence.id, title: "Uncancel Me \(Int(Date().timeIntervalSince1970))")
        guard TestAccountAPIClient.cancelTask(token: session.token, id: task.id) != nil else {
            throw XCTSkip("Could not cancel task via API — skipping uncancel test")
        }

        navigateToTasks()

        // Pull to refresh until the cancelled task is visible
        let taskText = app.staticTexts[task.title]
        pullToRefreshUntilVisible(taskText)
        guard taskText.waitForExistence(timeout: loginTimeout) else {
            throw XCTSkip("Cancelled task '\(task.title)' not visible — may require a Cancelled filter to be active")
        }
        taskText.forceTap()

        // Look for an uncancel / reopen / restore action
        let uncancelButton = app.buttons.containing(
            NSPredicate(format: "label CONTAINS[c] 'Uncancel' OR label CONTAINS[c] 'Reopen' OR label CONTAINS[c] 'Restore'")
        ).firstMatch

        guard uncancelButton.waitForExistence(timeout: defaultTimeout) else {
            throw XCTSkip("No uncancel button found — feature may not yet be implemented in UI")
        }
        uncancelButton.forceTap()

        // After uncancelling, the task should no longer show a Cancelled status label
        let cancelledLabel = app.staticTexts.containing(
            NSPredicate(format: "label CONTAINS[c] 'Cancelled'")
        ).firstMatch
        XCTAssertFalse(
            cancelledLabel.waitForExistence(timeout: defaultTimeout),
            "Task should no longer display 'Cancelled' status after being restored"
        )
    }

    // MARK: - TASK-012: Delete Task

    func testTASK012_DeleteTaskUpdatesViews() {
        // Create a task via UI first (since Kanban board uses cached data)
        let residence = cleaner.seedResidence()
        navigateToTasks()

        let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch
        let emptyAddButton = app.buttons.containing(
            NSPredicate(format: "label CONTAINS[c] 'Add' OR label CONTAINS[c] 'Create'")
        ).firstMatch

        let addVisible = addButton.waitForExistence(timeout: defaultTimeout) || emptyAddButton.waitForExistence(timeout: 3)
        XCTAssertTrue(addVisible, "Add task button should be visible")

        if addButton.exists && addButton.isHittable {
            addButton.forceTap()
        } else {
            emptyAddButton.forceTap()
        }

        let titleField = app.textFields[AccessibilityIdentifiers.Task.titleField]
        titleField.waitForExistenceOrFail(timeout: defaultTimeout)
        let uniqueTitle = "Delete Task \(Int(Date().timeIntervalSince1970))"
        titleField.forceTap()
        _ = app.keyboards.firstMatch.waitForExistence(timeout: 3)
        titleField.typeText(uniqueTitle)

        let saveButton = app.buttons[AccessibilityIdentifiers.Task.saveButton]
        let scrollContainer = app.scrollViews.firstMatch.exists ? app.scrollViews.firstMatch : app.collectionViews.firstMatch
        if scrollContainer.exists {
            saveButton.scrollIntoView(in: scrollContainer)
        }
        saveButton.forceTap()

        // Wait for the task to appear in the Kanban board
        let taskText = app.staticTexts[uniqueTitle]
        taskText.waitForExistenceOrFail(timeout: loginTimeout)

        // Tap the "Actions" menu on the task card to reveal cancel option
        let actionsMenu = app.buttons.containing(
            NSPredicate(format: "label CONTAINS[c] 'Actions'")
        ).firstMatch
        if actionsMenu.waitForExistence(timeout: defaultTimeout) {
            actionsMenu.forceTap()
        } else {
            taskText.forceTap()
        }

        // Tap cancel (tasks use "Cancel Task" semantics)
        let deleteButton = app.buttons[AccessibilityIdentifiers.Task.deleteButton]
        if !deleteButton.waitForExistence(timeout: defaultTimeout) {
            let cancelTask = app.buttons.containing(
                NSPredicate(format: "label CONTAINS[c] 'Cancel Task'")
            ).firstMatch
            cancelTask.waitForExistenceOrFail(timeout: 5)
            cancelTask.forceTap()
        } else {
            deleteButton.forceTap()
        }

        // Confirm cancellation
        let confirmDelete = app.alerts.buttons.containing(
            NSPredicate(format: "label CONTAINS[c] 'Confirm' OR label CONTAINS[c] 'Yes' OR label CONTAINS[c] 'Cancel Task'")
        ).firstMatch
        let alertConfirmButton = app.buttons[AccessibilityIdentifiers.Alert.confirmButton]

        if alertConfirmButton.waitForExistence(timeout: defaultTimeout) {
            alertConfirmButton.tap()
        } else if confirmDelete.waitForExistence(timeout: defaultTimeout) {
            confirmDelete.tap()
        }

        // Refresh the task list (kanban uses toolbar button, not pull-to-refresh)
        refreshTasks()

        // Verify the task is removed or moved to a different column
        let deletedTask = app.staticTexts[uniqueTitle]
        XCTAssertTrue(
            deletedTask.waitForNonExistence(timeout: loginTimeout),
            "Cancelled task should no longer appear in active views"
        )
    }
}
