package com.tt.honeyDue.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tt.honeyDue.data.DataManager
import com.tt.honeyDue.models.AuthResponse
import com.tt.honeyDue.models.BulkCreateTasksRequest
import com.tt.honeyDue.models.LoginRequest
import com.tt.honeyDue.models.RegisterRequest
import com.tt.honeyDue.models.ResidenceCreateRequest
import com.tt.honeyDue.models.TaskCreateRequest
import com.tt.honeyDue.models.TaskSuggestionsResponse
import com.tt.honeyDue.models.TaskTemplatesGroupedResponse
import com.tt.honeyDue.models.VerifyEmailRequest
import com.tt.honeyDue.network.ApiResult
import com.tt.honeyDue.network.APILayer
import com.tt.honeyDue.repository.LookupsRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

/**
 * User's intent during onboarding
 */
enum class OnboardingIntent {
    UNKNOWN,
    START_FRESH,    // Creating a new residence
    JOIN_EXISTING   // Joining with a share code
}

/**
 * Steps in the onboarding flow
 */
enum class OnboardingStep {
    WELCOME,
    VALUE_PROPS,
    NAME_RESIDENCE,
    CREATE_ACCOUNT,
    VERIFY_EMAIL,
    JOIN_RESIDENCE,
    RESIDENCE_LOCATION,
    HOME_PROFILE,
    FIRST_TASK,
    SUBSCRIPTION_UPSELL
}

/**
 * ViewModel for managing the onboarding flow state
 */
class OnboardingViewModel : ViewModel() {

    private val _currentStep = MutableStateFlow(OnboardingStep.WELCOME)
    val currentStep: StateFlow<OnboardingStep> = _currentStep

    private val _userIntent = MutableStateFlow(OnboardingIntent.UNKNOWN)
    val userIntent: StateFlow<OnboardingIntent> = _userIntent

    private val _residenceName = MutableStateFlow("")
    val residenceName: StateFlow<String> = _residenceName

    private val _shareCode = MutableStateFlow("")
    val shareCode: StateFlow<String> = _shareCode

    // Registration state
    private val _registerState = MutableStateFlow<ApiResult<AuthResponse>>(ApiResult.Idle)
    val registerState: StateFlow<ApiResult<AuthResponse>> = _registerState

    // Login state (for returning users)
    private val _loginState = MutableStateFlow<ApiResult<AuthResponse>>(ApiResult.Idle)
    val loginState: StateFlow<ApiResult<AuthResponse>> = _loginState

    // Email verification state
    private val _verifyEmailState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val verifyEmailState: StateFlow<ApiResult<Unit>> = _verifyEmailState

    // Residence creation state
    private val _createResidenceState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val createResidenceState: StateFlow<ApiResult<Unit>> = _createResidenceState

    // Join residence state
    private val _joinResidenceState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val joinResidenceState: StateFlow<ApiResult<Unit>> = _joinResidenceState

    // Task creation state (bulk create)
    private val _createTasksState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val createTasksState: StateFlow<ApiResult<Unit>> = _createTasksState

    // Grouped templates for the Browse tab on the First-Task screen
    private val _templatesGroupedState = MutableStateFlow<ApiResult<TaskTemplatesGroupedResponse>>(ApiResult.Idle)
    val templatesGroupedState: StateFlow<ApiResult<TaskTemplatesGroupedResponse>> = _templatesGroupedState

    // ZIP code entered during onboarding (persisted on residence). Still
    // collected so the suggestion service can factor in the user's climate
    // zone as its 15th scoring condition.
    private val _postalCode = MutableStateFlow("")
    val postalCode: StateFlow<String> = _postalCode

    // Home profile fields
    private val _heatingType = MutableStateFlow<String?>(null)
    val heatingType: StateFlow<String?> = _heatingType

    private val _coolingType = MutableStateFlow<String?>(null)
    val coolingType: StateFlow<String?> = _coolingType

    private val _waterHeaterType = MutableStateFlow<String?>(null)
    val waterHeaterType: StateFlow<String?> = _waterHeaterType

    private val _roofType = MutableStateFlow<String?>(null)
    val roofType: StateFlow<String?> = _roofType

    private val _hasPool = MutableStateFlow(false)
    val hasPool: StateFlow<Boolean> = _hasPool

    private val _hasSprinklerSystem = MutableStateFlow(false)
    val hasSprinklerSystem: StateFlow<Boolean> = _hasSprinklerSystem

    private val _hasSeptic = MutableStateFlow(false)
    val hasSeptic: StateFlow<Boolean> = _hasSeptic

    private val _hasFireplace = MutableStateFlow(false)
    val hasFireplace: StateFlow<Boolean> = _hasFireplace

    private val _hasGarage = MutableStateFlow(false)
    val hasGarage: StateFlow<Boolean> = _hasGarage

    private val _hasBasement = MutableStateFlow(false)
    val hasBasement: StateFlow<Boolean> = _hasBasement

    private val _hasAttic = MutableStateFlow(false)
    val hasAttic: StateFlow<Boolean> = _hasAttic

    private val _exteriorType = MutableStateFlow<String?>(null)
    val exteriorType: StateFlow<String?> = _exteriorType

    private val _flooringPrimary = MutableStateFlow<String?>(null)
    val flooringPrimary: StateFlow<String?> = _flooringPrimary

    private val _landscapingType = MutableStateFlow<String?>(null)
    val landscapingType: StateFlow<String?> = _landscapingType

    // Task suggestions state
    private val _suggestionsState = MutableStateFlow<ApiResult<TaskSuggestionsResponse>>(ApiResult.Idle)
    val suggestionsState: StateFlow<ApiResult<TaskSuggestionsResponse>> = _suggestionsState

    // Whether onboarding is complete
    private val _isComplete = MutableStateFlow(false)
    val isComplete: StateFlow<Boolean> = _isComplete

    fun setUserIntent(intent: OnboardingIntent) {
        _userIntent.value = intent
    }

    fun setResidenceName(name: String) {
        _residenceName.value = name
    }

    fun setShareCode(code: String) {
        _shareCode.value = code
    }

    // Home profile setters
    fun setHeatingType(value: String?) { _heatingType.value = value }
    fun setCoolingType(value: String?) { _coolingType.value = value }
    fun setWaterHeaterType(value: String?) { _waterHeaterType.value = value }
    fun setRoofType(value: String?) { _roofType.value = value }
    fun setHasPool(value: Boolean) { _hasPool.value = value }
    fun setHasSprinklerSystem(value: Boolean) { _hasSprinklerSystem.value = value }
    fun setHasSeptic(value: Boolean) { _hasSeptic.value = value }
    fun setHasFireplace(value: Boolean) { _hasFireplace.value = value }
    fun setHasGarage(value: Boolean) { _hasGarage.value = value }
    fun setHasBasement(value: Boolean) { _hasBasement.value = value }
    fun setHasAttic(value: Boolean) { _hasAttic.value = value }
    fun setExteriorType(value: String?) { _exteriorType.value = value }
    fun setFlooringPrimary(value: String?) { _flooringPrimary.value = value }
    fun setLandscapingType(value: String?) { _landscapingType.value = value }

    /**
     * Load personalized task suggestions for the given residence.
     */
    fun loadSuggestions(residenceId: Int) {
        viewModelScope.launch {
            _suggestionsState.value = ApiResult.Loading
            _suggestionsState.value = APILayer.getTaskSuggestions(residenceId)
        }
    }

    /**
     * Move to the next step in the flow
     * Flow: Welcome → Features → Name Residence → Create Account → Verify → Tasks → Upsell
     */
    fun nextStep() {
        _currentStep.value = when (_currentStep.value) {
            OnboardingStep.WELCOME -> {
                if (_userIntent.value == OnboardingIntent.JOIN_EXISTING) {
                    OnboardingStep.CREATE_ACCOUNT
                } else {
                    OnboardingStep.VALUE_PROPS
                }
            }
            OnboardingStep.VALUE_PROPS -> OnboardingStep.NAME_RESIDENCE
            OnboardingStep.NAME_RESIDENCE -> OnboardingStep.CREATE_ACCOUNT
            OnboardingStep.CREATE_ACCOUNT -> OnboardingStep.VERIFY_EMAIL
            OnboardingStep.VERIFY_EMAIL -> {
                if (_userIntent.value == OnboardingIntent.JOIN_EXISTING) {
                    OnboardingStep.JOIN_RESIDENCE
                } else {
                    OnboardingStep.HOME_PROFILE
                }
            }
            OnboardingStep.JOIN_RESIDENCE -> {
                completeOnboarding()
                OnboardingStep.JOIN_RESIDENCE
            }
            OnboardingStep.RESIDENCE_LOCATION -> OnboardingStep.HOME_PROFILE  // Skip past if somehow reached
            OnboardingStep.HOME_PROFILE -> OnboardingStep.FIRST_TASK
            OnboardingStep.FIRST_TASK -> {
                completeOnboarding()
                OnboardingStep.FIRST_TASK
            }
            OnboardingStep.SUBSCRIPTION_UPSELL -> {
                completeOnboarding()
                OnboardingStep.SUBSCRIPTION_UPSELL
            }
        }
    }

    /**
     * Go to a specific step
     */
    fun goToStep(step: OnboardingStep) {
        _currentStep.value = step
    }

    /**
     * Go back to the previous step
     */
    fun previousStep() {
        _currentStep.value = when (_currentStep.value) {
            OnboardingStep.VALUE_PROPS -> OnboardingStep.WELCOME
            OnboardingStep.NAME_RESIDENCE -> OnboardingStep.VALUE_PROPS
            OnboardingStep.CREATE_ACCOUNT -> {
                if (_userIntent.value == OnboardingIntent.JOIN_EXISTING) {
                    OnboardingStep.WELCOME
                } else {
                    OnboardingStep.NAME_RESIDENCE
                }
            }
            OnboardingStep.VERIFY_EMAIL -> OnboardingStep.CREATE_ACCOUNT
            else -> _currentStep.value
        }
    }

    /**
     * Skip the current step (for skippable screens)
     */
    fun skipStep() {
        when (_currentStep.value) {
            OnboardingStep.VALUE_PROPS,
            OnboardingStep.HOME_PROFILE -> nextStep()
            OnboardingStep.JOIN_RESIDENCE,
            OnboardingStep.FIRST_TASK,
            OnboardingStep.SUBSCRIPTION_UPSELL -> completeOnboarding()
            else -> {}
        }
    }

    /**
     * Register a new user
     */
    fun register(username: String, email: String, password: String) {
        viewModelScope.launch {
            _registerState.value = ApiResult.Loading
            val result = APILayer.register(
                RegisterRequest(
                    username = username,
                    email = email,
                    password = password
                )
            )
            _registerState.value = when (result) {
                is ApiResult.Success -> {
                    DataManager.setAuthToken(result.data.token)
                    DataManager.setCurrentUser(result.data.user)
                    LookupsRepository.initialize()
                    ApiResult.Success(result.data)
                }
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    /**
     * Login an existing user
     */
    fun login(username: String, password: String) {
        viewModelScope.launch {
            _loginState.value = ApiResult.Loading
            val result = APILayer.login(LoginRequest(username, password))
            _loginState.value = when (result) {
                is ApiResult.Success -> {
                    LookupsRepository.initialize()
                    ApiResult.Success(result.data)
                }
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    /**
     * Verify email with 6-digit code
     */
    fun verifyEmail(code: String) {
        viewModelScope.launch {
            _verifyEmailState.value = ApiResult.Loading
            val token = DataManager.authToken.value ?: run {
                _verifyEmailState.value = ApiResult.Error("Not authenticated")
                return@launch
            }
            val result = APILayer.verifyEmail(token, VerifyEmailRequest(code = code))
            _verifyEmailState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(Unit)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    /**
     * Create the residence with the name from onboarding
     */
    fun createResidence() {
        viewModelScope.launch {
            if (_residenceName.value.isBlank()) {
                _createResidenceState.value = ApiResult.Success(Unit)
                return@launch
            }

            _createResidenceState.value = ApiResult.Loading

            val result = APILayer.createResidence(
                ResidenceCreateRequest(
                    name = _residenceName.value,
                    propertyTypeId = null,
                    streetAddress = null,
                    apartmentUnit = null,
                    city = null,
                    stateProvince = null,
                    postalCode = _postalCode.value.takeIf { it.isNotBlank() },
                    country = null,
                    bedrooms = null,
                    bathrooms = null,
                    squareFootage = null,
                    lotSize = null,
                    yearBuilt = null,
                    description = null,
                    purchaseDate = null,
                    purchasePrice = null,
                    isPrimary = true,
                    heatingType = _heatingType.value,
                    coolingType = _coolingType.value,
                    waterHeaterType = _waterHeaterType.value,
                    roofType = _roofType.value,
                    hasPool = _hasPool.value.takeIf { it },
                    hasSprinklerSystem = _hasSprinklerSystem.value.takeIf { it },
                    hasSeptic = _hasSeptic.value.takeIf { it },
                    hasFireplace = _hasFireplace.value.takeIf { it },
                    hasGarage = _hasGarage.value.takeIf { it },
                    hasBasement = _hasBasement.value.takeIf { it },
                    hasAttic = _hasAttic.value.takeIf { it },
                    exteriorType = _exteriorType.value,
                    flooringPrimary = _flooringPrimary.value,
                    landscapingType = _landscapingType.value
                )
            )

            _createResidenceState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(Unit)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Failed to create residence")
            }
        }
    }

    /**
     * Join an existing residence with a share code
     */
    fun joinResidence(code: String) {
        viewModelScope.launch {
            _joinResidenceState.value = ApiResult.Loading
            val result = APILayer.joinWithCode(code)
            _joinResidenceState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(Unit)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Failed to join residence")
            }
        }
    }

    /**
     * Create the user's selected tasks in a single atomic bulk request.
     * The server runs the inserts inside one transaction, so either every
     * entry lands or none do — no risk of a half-populated kanban board
     * if the network flakes mid-batch.
     *
     * [residenceId] overrides every entry's residence_id on the server side;
     * pass the just-created residence's ID.
     */
    fun createTasks(residenceId: Int, taskRequests: List<TaskCreateRequest>) {
        viewModelScope.launch {
            if (taskRequests.isEmpty()) {
                _createTasksState.value = ApiResult.Success(Unit)
                return@launch
            }

            _createTasksState.value = ApiResult.Loading

            val request = BulkCreateTasksRequest(
                residenceId = residenceId,
                tasks = taskRequests
            )
            _createTasksState.value = when (val result = APILayer.bulkCreateTasks(request)) {
                is ApiResult.Success -> ApiResult.Success(Unit)
                is ApiResult.Error -> ApiResult.Error(result.message, result.code)
                is ApiResult.Loading -> ApiResult.Loading
                is ApiResult.Idle -> ApiResult.Idle
            }
        }
    }

    /**
     * Load the flat template catalog grouped by category. Feeds the Browse
     * tab on the First-Task screen; no caching special-case because
     * APILayer.getTaskTemplatesGrouped already reads from DataManager first.
     */
    fun loadTemplatesGrouped(forceRefresh: Boolean = false) {
        viewModelScope.launch {
            _templatesGroupedState.value = ApiResult.Loading
            _templatesGroupedState.value = APILayer.getTaskTemplatesGrouped(forceRefresh = forceRefresh)
        }
    }

    /**
     * Mark onboarding as complete
     */
    fun completeOnboarding() {
        _isComplete.value = true
    }

    /**
     * Reset all state (useful for testing)
     */
    fun reset() {
        _currentStep.value = OnboardingStep.WELCOME
        _userIntent.value = OnboardingIntent.UNKNOWN
        _residenceName.value = ""
        _shareCode.value = ""
        _registerState.value = ApiResult.Idle
        _loginState.value = ApiResult.Idle
        _verifyEmailState.value = ApiResult.Idle
        _createResidenceState.value = ApiResult.Idle
        _joinResidenceState.value = ApiResult.Idle
        _createTasksState.value = ApiResult.Idle
        _templatesGroupedState.value = ApiResult.Idle
        _postalCode.value = ""
        _heatingType.value = null
        _coolingType.value = null
        _waterHeaterType.value = null
        _roofType.value = null
        _hasPool.value = false
        _hasSprinklerSystem.value = false
        _hasSeptic.value = false
        _hasFireplace.value = false
        _hasGarage.value = false
        _hasBasement.value = false
        _hasAttic.value = false
        _exteriorType.value = null
        _flooringPrimary.value = null
        _landscapingType.value = null
        _suggestionsState.value = ApiResult.Idle
        _isComplete.value = false
    }

    fun resetRegisterState() {
        _registerState.value = ApiResult.Idle
    }

    fun resetLoginState() {
        _loginState.value = ApiResult.Idle
    }

    fun resetVerifyEmailState() {
        _verifyEmailState.value = ApiResult.Idle
    }
}
