package com.tt.honeyDue.ui.screens.residence

import kotlin.time.Clock
import kotlin.time.ExperimentalTime
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime

/**
 * Pure-function validators for the residence create/edit form.
 *
 * Parity with iOS:
 *  - `iosApp/iosApp/ResidenceFormView.swift::validateForm()` — only `name`
 *    is required (the iOS `canSave` and `validateForm` both gate solely on
 *    `!name.isEmpty`). We keep that contract: all address/feature fields are
 *    optional.
 *  - `iosApp/iosApp/Core/FormStates/ResidenceFormState.swift` — numeric
 *    fields use `asOptionalInt`/`asOptionalDouble` which silently drop
 *    unparseable values. On KMM we surface a user-facing error instead so
 *    the client isn't dropping input on the floor, matching the phrasing
 *    used by Stream W's `TaskFormValidation`.
 *
 * Each function returns `null` when the value is valid, or an error
 * message otherwise. Callers compose these into a [ResidenceFormErrors]
 * snapshot.
 */
object ResidenceFormValidation {

    /** Maximum length enforced by the backend's `name` column. */
    private const val NAME_MAX_LENGTH = 100

    /** iOS uses `yearBuilt` as a 4-digit integer with no UI range gate; the
     *  API accepts any Int. We bound on the client to catch obvious typos. */
    private const val YEAR_BUILT_MIN = 1800

    fun validateName(value: String): String? {
        if (value.isBlank()) return "Name is required"
        if (value.length > NAME_MAX_LENGTH) {
            return "Name must be $NAME_MAX_LENGTH characters or fewer"
        }
        return null
    }

    /**
     * Optional integer >= 0. Matches iOS `bedrooms.value.asOptionalInt` —
     * iOS allows 0 silently, so do we.
     */
    fun validateBedrooms(value: String): String? {
        if (value.isBlank()) return null
        val n = value.toIntOrNull()
        if (n == null || n < 0) {
            return "Bedrooms must be a non-negative whole number"
        }
        return null
    }

    /** Optional double >= 0. Matches iOS `bathrooms.value.asOptionalDouble`. */
    fun validateBathrooms(value: String): String? {
        if (value.isBlank()) return null
        val n = value.toDoubleOrNull()
        if (n == null || n < 0.0) {
            return "Bathrooms must be a non-negative number"
        }
        return null
    }

    /** Optional integer > 0. A 0-square-foot property is nonsensical. */
    fun validateSquareFootage(value: String): String? {
        if (value.isBlank()) return null
        val n = value.toIntOrNull()
        if (n == null || n <= 0) {
            return "Square footage must be a positive whole number"
        }
        return null
    }

    /** Optional double > 0. Acres typically, but unit-agnostic. */
    fun validateLotSize(value: String): String? {
        if (value.isBlank()) return null
        val n = value.toDoubleOrNull()
        if (n == null || n <= 0.0) {
            return "Lot size must be a positive number"
        }
        return null
    }

    /**
     * Optional 4-digit year between [YEAR_BUILT_MIN] and the current year
     * inclusive. iOS coerces via `asOptionalInt` with no range gate; we
     * tighten on the client.
     */
    fun validateYearBuilt(value: String, currentYear: Int = defaultCurrentYear()): String? {
        if (value.isBlank()) return null
        if (value.length != 4) return "Year built must be a 4-digit year"
        val n = value.toIntOrNull() ?: return "Year built must be a 4-digit year"
        if (n < YEAR_BUILT_MIN || n > currentYear) {
            return "Year built must be between $YEAR_BUILT_MIN and the current year"
        }
        return null
    }

    @OptIn(ExperimentalTime::class)
    private fun defaultCurrentYear(): Int {
        val nowMillis = Clock.System.now().toEpochMilliseconds()
        return Instant.fromEpochMilliseconds(nowMillis)
            .toLocalDateTime(TimeZone.currentSystemDefault())
            .year
    }
}
