package com.tt.honeyDue.ui.screens

import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.test.performTextReplacement
import com.tt.honeyDue.testing.AccessibilityIds
import com.tt.honeyDue.ui.BaseScreen

/**
 * Page object trio for the residence surface.
 * Mirrors iOS `ResidenceListScreen`, `ResidenceFormScreen`, and
 * `ResidenceDetailScreen` page objects used by `Suite4_ComprehensiveResidenceTests`.
 *
 * Everything here drives off [AccessibilityIds.Residence] so iOS + Android
 * share the same selectors. When the production screen changes, update the
 * `testTag` on the screen first, then the constants in `AccessibilityIds`.
 */
class ResidencesListPageObject(rule: ComposeTestRule) : BaseScreen(rule) {

    fun waitForLoad() {
        // Either the add-button (list exists) or the empty-state view should appear.
        rule.waitUntil(DEFAULT_TIMEOUT_MS) {
            exists(AccessibilityIds.Residence.addButton) ||
                exists(AccessibilityIds.Residence.emptyStateView) ||
                exists(AccessibilityIds.Residence.emptyStateButton)
        }
    }

    fun tapAddResidence(): ResidencesFormPageObject {
        waitForLoad()
        // Prefer toolbar add button; fall back to empty-state add button.
        if (exists(AccessibilityIds.Residence.addButton)) {
            tag(AccessibilityIds.Residence.addButton).performClick()
        } else if (exists(AccessibilityIds.Residence.addFab)) {
            tag(AccessibilityIds.Residence.addFab).performClick()
        } else {
            tag(AccessibilityIds.Residence.emptyStateButton).performClick()
        }
        return ResidencesFormPageObject(rule)
    }

    fun tapJoinResidence() {
        waitForLoad()
        tag(AccessibilityIds.Residence.joinButton).performClick()
    }

    /** Returns a node interaction for a residence row labelled with [name]. */
    fun residenceRow(name: String): SemanticsNodeInteraction =
        rule.onNode(hasText(name, substring = true), useUnmergedTree = true)

    /** Taps the first residence in the list with the given display name. */
    fun openResidence(name: String): ResidencesDetailPageObject {
        rule.waitUntil(DEFAULT_TIMEOUT_MS) {
            try {
                residenceRow(name).assertExists()
                true
            } catch (e: AssertionError) {
                false
            }
        }
        residenceRow(name).performClick()
        return ResidencesDetailPageObject(rule)
    }

    override fun isDisplayed(): Boolean =
        exists(AccessibilityIds.Residence.addButton) ||
            exists(AccessibilityIds.Residence.emptyStateView)
}

class ResidencesFormPageObject(rule: ComposeTestRule) : BaseScreen(rule) {

    fun waitForLoad() { waitFor(AccessibilityIds.Residence.nameField) }

    fun enterName(value: String): ResidencesFormPageObject {
        waitForLoad()
        tag(AccessibilityIds.Residence.nameField).performTextInput(value)
        return this
    }

    fun replaceName(value: String): ResidencesFormPageObject {
        waitForLoad()
        tag(AccessibilityIds.Residence.nameField).performTextReplacement(value)
        return this
    }

    fun enterStreet(value: String): ResidencesFormPageObject {
        waitFor(AccessibilityIds.Residence.streetAddressField)
        tag(AccessibilityIds.Residence.streetAddressField).performTextInput(value)
        return this
    }

    fun enterCity(value: String): ResidencesFormPageObject {
        waitFor(AccessibilityIds.Residence.cityField)
        tag(AccessibilityIds.Residence.cityField).performTextInput(value)
        return this
    }

    fun enterStateProvince(value: String): ResidencesFormPageObject {
        waitFor(AccessibilityIds.Residence.stateProvinceField)
        tag(AccessibilityIds.Residence.stateProvinceField).performTextInput(value)
        return this
    }

    fun enterPostalCode(value: String): ResidencesFormPageObject {
        waitFor(AccessibilityIds.Residence.postalCodeField)
        tag(AccessibilityIds.Residence.postalCodeField).performTextInput(value)
        return this
    }

    fun fillAddress(street: String, city: String, stateProvince: String, postal: String): ResidencesFormPageObject {
        enterStreet(street)
        enterCity(city)
        enterStateProvince(stateProvince)
        enterPostalCode(postal)
        return this
    }

    fun tapSave() {
        waitFor(AccessibilityIds.Residence.saveButton)
        tag(AccessibilityIds.Residence.saveButton).performClick()
    }

    fun tapCancel() {
        waitFor(AccessibilityIds.Residence.formCancelButton)
        tag(AccessibilityIds.Residence.formCancelButton).performClick()
    }

    fun assertSaveDisabled() {
        waitFor(AccessibilityIds.Residence.saveButton)
        tag(AccessibilityIds.Residence.saveButton).assertIsNotEnabled()
    }

    /** Waits until the form dismisses (save button no longer exists). */
    fun waitForDismiss(timeoutMs: Long = DEFAULT_TIMEOUT_MS) {
        rule.waitUntil(timeoutMs) { !exists(AccessibilityIds.Residence.saveButton) }
    }

    override fun isDisplayed(): Boolean = exists(AccessibilityIds.Residence.nameField)
}

class ResidencesDetailPageObject(rule: ComposeTestRule) : BaseScreen(rule) {

    fun waitForLoad() { waitFor(AccessibilityIds.Residence.editButton) }

    fun tapEdit(): ResidencesFormPageObject {
        waitForLoad()
        tag(AccessibilityIds.Residence.editButton).performClick()
        return ResidencesFormPageObject(rule)
    }

    fun tapDelete() {
        waitFor(AccessibilityIds.Residence.deleteButton)
        tag(AccessibilityIds.Residence.deleteButton).performClick()
    }

    fun confirmDelete() {
        waitFor(AccessibilityIds.Residence.confirmDeleteButton)
        tag(AccessibilityIds.Residence.confirmDeleteButton).performClick()
    }

    override fun isDisplayed(): Boolean = exists(AccessibilityIds.Residence.editButton)
}
