import XCTest

/// Integration tests for residence CRUD against the real local backend.
///
/// Uses a seeded admin account. Data is seeded via API and cleaned up in tearDown.
final class ResidenceIntegrationTests: 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 Residence

    func testRES_CreateResidenceAppearsInList() {
        navigateToResidences()

        let residenceList = ResidenceListScreen(app: app)
        residenceList.waitForLoad(timeout: defaultTimeout)

        residenceList.openCreateResidence()

        let form = ResidenceFormScreen(app: app)
        form.waitForLoad(timeout: defaultTimeout)

        let uniqueName = "IntTest Residence \(Int(Date().timeIntervalSince1970))"
        form.enterName(uniqueName)
        form.save()

        let newResidence = app.staticTexts[uniqueName]
        XCTAssertTrue(
            newResidence.waitForExistence(timeout: loginTimeout),
            "Newly created residence should appear in the list"
        )
    }

    // MARK: - Edit Residence

    func testRES_EditResidenceUpdatesInList() {
        // Seed a residence via API so we have a known target to edit
        let seeded = cleaner.seedResidence(name: "Edit Target \(Int(Date().timeIntervalSince1970))")

        navigateToResidences()
        pullToRefresh()

        let residenceList = ResidenceListScreen(app: app)
        residenceList.waitForLoad(timeout: defaultTimeout)

        // Find and tap the seeded residence
        let card = app.staticTexts[seeded.name]
        pullToRefreshUntilVisible(card, maxRetries: 3)
        card.waitForExistenceOrFail(timeout: loginTimeout)
        card.forceTap()

        // Tap edit button on detail view
        let editButton = app.buttons[AccessibilityIdentifiers.Residence.editButton]
        editButton.waitForExistenceOrFail(timeout: defaultTimeout)
        editButton.forceTap()

        let form = ResidenceFormScreen(app: app)
        form.waitForLoad(timeout: defaultTimeout)

        // Clear and re-enter name
        let nameField = form.nameField
        nameField.waitUntilHittable(timeout: 10).tap()
        nameField.press(forDuration: 1.0)
        let selectAll = app.menuItems["Select All"]
        if selectAll.waitForExistence(timeout: 2) {
            selectAll.tap()
        }

        let updatedName = "Updated Res \(Int(Date().timeIntervalSince1970))"
        nameField.typeText(updatedName)
        form.save()

        let updatedText = app.staticTexts[updatedName]
        XCTAssertTrue(
            updatedText.waitForExistence(timeout: loginTimeout),
            "Updated residence name should appear after edit"
        )
    }

    // MARK: - RES-007: Primary Residence

    func test18_setPrimaryResidence() {
        // Seed two residences via API; the second one will be promoted to primary
        let firstResidence = cleaner.seedResidence(name: "Primary Test A \(Int(Date().timeIntervalSince1970))")
        let secondResidence = cleaner.seedResidence(name: "Primary Test B \(Int(Date().timeIntervalSince1970))")

        navigateToResidences()
        pullToRefresh()

        let residenceList = ResidenceListScreen(app: app)
        residenceList.waitForLoad(timeout: defaultTimeout)

        // Open the second residence's detail
        let secondCard = app.staticTexts[secondResidence.name]
        pullToRefreshUntilVisible(secondCard, maxRetries: 3)
        secondCard.waitForExistenceOrFail(timeout: loginTimeout)
        secondCard.forceTap()

        // Tap edit
        let editButton = app.buttons[AccessibilityIdentifiers.Residence.editButton]
        editButton.waitForExistenceOrFail(timeout: defaultTimeout)
        editButton.forceTap()

        let form = ResidenceFormScreen(app: app)
        form.waitForLoad(timeout: defaultTimeout)

        // Find and toggle the "is primary" toggle
        let isPrimaryToggle = app.switches[AccessibilityIdentifiers.Residence.isPrimaryToggle]
        isPrimaryToggle.scrollIntoView(in: app.scrollViews.firstMatch)
        isPrimaryToggle.waitForExistenceOrFail(timeout: defaultTimeout)

        // Toggle it on (value "0" means off, "1" means on)
        if (isPrimaryToggle.value as? String) == "0" {
            isPrimaryToggle.forceTap()
        }

        form.save()

        // After saving, a primary indicator should be visible — either a label,
        // badge, or the toggle being on in the refreshed detail view.
        let primaryIndicator = app.staticTexts.containing(
            NSPredicate(format: "label CONTAINS[c] 'Primary'")
        ).firstMatch

        let primaryBadge = app.images.containing(
            NSPredicate(format: "label CONTAINS[c] 'Primary'")
        ).firstMatch

        let indicatorVisible = primaryIndicator.waitForExistence(timeout: loginTimeout)
            || primaryBadge.waitForExistence(timeout: 3)

        XCTAssertTrue(
            indicatorVisible,
            "A primary residence indicator should appear after setting '\(secondResidence.name)' as primary"
        )

        // Clean up: remove unused firstResidence id from tracking (already tracked via cleaner)
        _ = firstResidence
    }

    // MARK: - OFF-004: Double Submit Protection

    func test19_doubleSubmitProtection() {
        navigateToResidences()

        let residenceList = ResidenceListScreen(app: app)
        residenceList.waitForLoad(timeout: defaultTimeout)

        residenceList.openCreateResidence()

        let form = ResidenceFormScreen(app: app)
        form.waitForLoad(timeout: defaultTimeout)

        let uniqueName = "DoubleSubmit \(Int(Date().timeIntervalSince1970))"
        form.enterName(uniqueName)

        // Rapidly tap save twice to test double-submit protection
        let saveButton = app.buttons[AccessibilityIdentifiers.Residence.saveButton]
        saveButton.scrollIntoView(in: app.scrollViews.firstMatch)
        saveButton.forceTap()
        // Second tap immediately after — if the button is already disabled this will be a no-op
        if saveButton.isHittable {
            saveButton.forceTap()
        }

        // Wait for the form to dismiss (sheet closes, we return to the list)
        let formDismissed = saveButton.waitForNonExistence(timeout: loginTimeout)
        XCTAssertTrue(formDismissed, "Form should dismiss after save")

        // Back on the residences list — count how many cells with the unique name exist
        let matchingTexts = app.staticTexts.matching(
            NSPredicate(format: "label == %@", uniqueName)
        )

        // Allow time for the list to fully load
        _ = app.staticTexts[uniqueName].waitForExistence(timeout: defaultTimeout)

        XCTAssertEqual(
            matchingTexts.count, 1,
            "Only one residence named '\(uniqueName)' should exist — double-submit protection should prevent duplicates"
        )

        // Track the created residence for cleanup
        if let residences = TestAccountAPIClient.listResidences(token: session.token) {
            if let created = residences.first(where: { $0.name == uniqueName }) {
                cleaner.trackResidence(created.id)
            }
        }
    }

    // MARK: - Delete Residence

    func testRES_DeleteResidenceRemovesFromList() {
        // Seed a residence via API — don't track it since we'll delete through the UI
        let deleteName = "Delete Me \(Int(Date().timeIntervalSince1970))"
        TestDataSeeder.createResidence(token: session.token, name: deleteName)

        navigateToResidences()
        pullToRefresh()

        let residenceList = ResidenceListScreen(app: app)
        residenceList.waitForLoad(timeout: defaultTimeout)

        // Find and tap the seeded residence
        let target = app.staticTexts[deleteName]
        pullToRefreshUntilVisible(target, maxRetries: 3)
        target.waitForExistenceOrFail(timeout: loginTimeout)
        target.forceTap()

        // Tap delete button
        let deleteButton = app.buttons[AccessibilityIdentifiers.Residence.deleteButton]
        deleteButton.waitForExistenceOrFail(timeout: defaultTimeout)
        deleteButton.forceTap()

        // Confirm deletion in alert
        let confirmButton = app.buttons[AccessibilityIdentifiers.Alert.confirmButton]
        let alertDelete = app.alerts.buttons.containing(
            NSPredicate(format: "label CONTAINS[c] 'Delete' OR label CONTAINS[c] 'Confirm'")
        ).firstMatch

        if confirmButton.waitForExistence(timeout: defaultTimeout) {
            confirmButton.tap()
        } else if alertDelete.waitForExistence(timeout: defaultTimeout) {
            alertDelete.tap()
        }

        let deletedResidence = app.staticTexts[deleteName]
        XCTAssertTrue(
            deletedResidence.waitForNonExistence(timeout: loginTimeout),
            "Deleted residence should no longer appear in the list"
        )
    }
}
