package com.tt.honeyDue.ui.screens.task

import kotlinx.datetime.LocalDate
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue

/**
 * Behaviour spec for TaskFormState — the container that wires TaskFormFields
 * to the pure validators and to typed request builders.
 */
class TaskFormStateTest {

    private fun validFields(
        residenceId: Int? = 10,
    ) = TaskFormFields(
        title = "Change HVAC filter",
        description = "Replace the filter in the hallway unit",
        priorityId = 1,
        categoryId = 2,
        frequencyId = 3,
        dueDate = LocalDate(2026, 5, 1),
        estimatedCost = "25.50",
        residenceId = residenceId,
    )

    @Test
    fun empty_fields_isValid_false_and_toCreateRequest_null() {
        val state = TaskFormState()
        assertFalse(state.isValid)
        assertNull(state.toCreateRequest())
    }

    @Test
    fun empty_fields_errors_populated_for_all_required_fields() {
        val state = TaskFormState()
        val errors = state.errors
        assertEquals("Title is required", errors.title)
        assertEquals("Please select a priority", errors.priorityId)
        assertEquals("Please select a category", errors.categoryId)
        assertEquals("Please select a frequency", errors.frequencyId)
        assertEquals("Property is required", errors.residenceId)
        assertNull(errors.estimatedCost) // empty cost is valid
    }

    @Test
    fun all_required_fields_set_isValid_true_and_errors_clear() {
        val state = TaskFormState(validFields())
        assertTrue(state.isValid)
        val errors = state.errors
        assertNull(errors.title)
        assertNull(errors.priorityId)
        assertNull(errors.categoryId)
        assertNull(errors.frequencyId)
        assertNull(errors.residenceId)
        assertNull(errors.estimatedCost)
    }

    @Test
    fun toCreateRequest_maps_fields_correctly_when_valid() {
        val state = TaskFormState(validFields())
        val request = state.toCreateRequest()
        assertNotNull(request)
        assertEquals(10, request.residenceId)
        assertEquals("Change HVAC filter", request.title)
        assertEquals("Replace the filter in the hallway unit", request.description)
        assertEquals(2, request.categoryId)
        assertEquals(1, request.priorityId)
        assertEquals(3, request.frequencyId)
        assertEquals("2026-05-01", request.dueDate)
        assertEquals(25.50, request.estimatedCost)
    }

    @Test
    fun toCreateRequest_blank_description_maps_to_null() {
        val state = TaskFormState(validFields().copy(description = "   "))
        val request = state.toCreateRequest()
        assertNotNull(request)
        assertNull(request.description)
    }

    @Test
    fun toCreateRequest_empty_estimatedCost_maps_to_null() {
        val state = TaskFormState(validFields().copy(estimatedCost = ""))
        val request = state.toCreateRequest()
        assertNotNull(request)
        assertNull(request.estimatedCost)
    }

    @Test
    fun toCreateRequest_null_dueDate_maps_to_null() {
        val state = TaskFormState(validFields().copy(dueDate = null))
        val request = state.toCreateRequest()
        assertNotNull(request)
        assertNull(request.dueDate)
    }

    @Test
    fun toCreateRequest_missing_residence_returns_null() {
        val state = TaskFormState(validFields(residenceId = null))
        assertFalse(state.isValid)
        assertNull(state.toCreateRequest())
    }

    @Test
    fun toCreateRequest_invalid_estimatedCost_returns_null() {
        val state = TaskFormState(validFields().copy(estimatedCost = "not a number"))
        assertFalse(state.isValid)
        assertNull(state.toCreateRequest())
        assertEquals(
            "Estimated cost must be a valid number",
            state.errors.estimatedCost,
        )
    }

    @Test
    fun update_recomputes_errors_and_isValid() {
        val state = TaskFormState()
        assertFalse(state.isValid)
        assertEquals("Title is required", state.errors.title)

        state.update(validFields())
        assertTrue(state.isValid)
        assertNull(state.errors.title)

        state.update(state.fields.copy(title = ""))
        assertFalse(state.isValid)
        assertEquals("Title is required", state.errors.title)
    }

    @Test
    fun validate_returns_current_errors_snapshot() {
        val state = TaskFormState()
        val snapshot = state.validate()
        assertEquals("Title is required", snapshot.title)
        assertEquals("Please select a priority", snapshot.priorityId)
    }

    @Test
    fun toUpdateRequest_maps_fields_correctly() {
        val state = TaskFormState(validFields())
        val request = state.toUpdateRequest(taskId = 42)
        assertNotNull(request)
        assertEquals("Change HVAC filter", request.title)
        assertEquals("Replace the filter in the hallway unit", request.description)
        assertEquals(2, request.categoryId)
        assertEquals(1, request.priorityId)
        assertEquals(3, request.frequencyId)
        assertEquals("2026-05-01", request.dueDate)
        assertEquals(25.50, request.estimatedCost)
    }

    @Test
    fun toUpdateRequest_when_invalid_returns_null() {
        val state = TaskFormState()
        assertNull(state.toUpdateRequest(taskId = 42))
    }

    @Test
    fun toUpdateRequest_ignores_residence_requirement() {
        // Edit mode doesn't need residenceId — the task already has one.
        val state = TaskFormState(validFields(residenceId = null))
        // State as a whole still reports invalid (residenceId missing), but
        // toUpdateRequest should still produce a request because updates do
        // not carry residenceId. This matches iOS where isEditMode bypasses
        // the residence check.
        val request = state.toUpdateRequest(taskId = 99)
        assertNotNull(request)
        assertEquals("Change HVAC filter", request.title)
    }

    @Test
    fun update_does_not_mutate_prior_fields_reference() {
        val state = TaskFormState()
        val initial = state.fields
        state.update(validFields())
        // `fields` has moved to the new value; original TaskFormFields is unchanged.
        assertEquals("", initial.title)
        assertEquals("Change HVAC filter", state.fields.title)
    }
}
