package app.closer.data.repository

import app.closer.data.local.DatePlanDao
import app.closer.data.local.DatePlanPreferenceDao
import app.closer.data.local.entity.DatePlanEntity
import app.closer.data.local.entity.DatePlanPreferenceEntity
import app.closer.data.remote.FirestoreDatePlanDataSource
import app.closer.domain.model.DatePlan
import app.closer.domain.model.DatePlanPreference
import app.closer.domain.model.DatePlanSuggestion
import app.closer.domain.model.DatePlanStatus
import app.closer.domain.repository.DatePlanRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Implementation of [DatePlanRepository].
 *
 * Local-first: Preferences stored in Room. Plans synced to Firestore when
 * explicitly shared/scheduled. Both partners contribute preferences; the
 * Builder assembles complete plans from those preferences.
 */
@Singleton
class DatePlanRepositoryImpl @Inject constructor(
    private val preferenceDataSource: FirestoreDatePlanDataSource,
    private val planDataSource: FirestoreDatePlanDataSource,
    private val preferenceDao: DatePlanPreferenceDao,
    private val planDao: DatePlanDao
) : DatePlanRepository {

    // ─── Preference methods ──────────────────────────────────────────────────

    override suspend fun getPreference(coupleId: String, dateIdeaId: String): DatePlanPreference? {
        // First check local cache
        val local = preferenceDao.getPreference(coupleId, dateIdeaId)
        if (local != null) return local.toDomain()

        // Fall back to Firestore
        return preferenceDataSource.getPreference(coupleId, dateIdeaId)
    }

    override suspend fun savePreference(preference: DatePlanPreference) {
        // Store in Room for local-first access
        val entity = preference.toEntity()
        preferenceDao.insert(entity)

        // Sync to Firestore
        preferenceDataSource.recordPreference(preference.coupleId, preference)
    }

    override fun observePreferences(coupleId: String): Flow<List<DatePlanPreference>> {
        return preferenceDataSource.observePreferences(coupleId)
    }

    // ─── Plan methods ────────────────────────────────────────────────────────

    override suspend fun getPlan(planId: String): DatePlan? {
        // First check local cache
        val local = planDao.getById(planId)
        if (local != null) return local.toDomain()

        // Fall back to Firestore
        return null
    }

    override suspend fun getPlansForCouple(coupleId: String): List<DatePlan> {
        // Get from local Room database
        return planDao.getByCoupleId(coupleId).map { it.toDomain() }
    }

    override suspend fun getPlansByStatus(coupleId: String, status: String): List<DatePlan> {
        // Get from local Room database
        return planDao.getByCoupleIdAndStatus(coupleId, status).map { it.toDomain() }
    }

    override suspend fun savePlan(plan: DatePlan) {
        val sanitized = plan.sanitized()
        val entity = sanitized.toEntity()

        if (sanitized.id.isEmpty()) {
            val newId = planDataSource.createPlan(sanitized.coupleId, sanitized)
            val updatedEntity = entity.copy(id = newId)
            planDao.insert(updatedEntity)
        } else {
            planDao.insert(entity)
            planDataSource.updatePlan(sanitized.coupleId, sanitized)
        }
    }

    override suspend fun updatePlanStatus(planId: String, status: String) {
        // Update local cache
        planDao.updateFirestoreId(planId, planId, status)

        // Update Firestore (fetch plan first to get current data)
        val plan = getPlan(planId)
        if (plan != null) {
            val updatedPlan = plan.copy(status = DatePlanStatus.fromFirestoreValue(status))
            planDataSource.updatePlan(updatedPlan.coupleId, updatedPlan)
        }
    }

    override suspend fun deletePlan(planId: String) {
        // Delete from local cache
        val plan = getPlan(planId)
        if (plan != null) {
            planDao.delete(plan.toEntity())
        }

        // Delete from Firestore - need coupleId
        // In a full implementation, we would fetch the plan's coupleId first
    }

    // ─── Builder methods ─────────────────────────────────────────────────────

    override suspend fun assemblePlanSuggestion(
        coupleId: String,
        dateIdeaId: String
    ): DatePlanSuggestion? {
        // Get preferences from both partners for this date idea
        val partnerAPreference = preferenceDao.getPreference(coupleId, dateIdeaId)
        val partnerBPreference = /* Get the other partner's preference */

        // For now, return a placeholder suggestion
        // In a full implementation, this would merge preferences from both partners
        return DatePlanSuggestion(
            activity = "Based on the selected date idea",
            food = "Suggested dining option based on budget",
            conversationPrompts = listOf("What made this date special?"),
            optionalChallenge = "Try something new together"
        )
    }

    // ─── Sanitization ────────────────────────────────────────────────────────

    private fun DatePlan.sanitized(): DatePlan = copy(
        scheduledTime = scheduledTime.take(MAX_TIME_LENGTH),
        duration = duration.take(MAX_DURATION_LENGTH),
        activity = activity.take(MAX_TEXT_LENGTH),
        food = food.take(MAX_TEXT_LENGTH),
        conversationPrompts = conversationPrompts
            .take(MAX_PROMPTS)
            .map { it.take(MAX_PROMPT_LENGTH) },
        optionalChallenge = optionalChallenge?.take(MAX_TEXT_LENGTH)
    )

    // ─── Mappers ─────────────────────────────────────────────────────────────

    private companion object {
        const val MAX_TIME_LENGTH = 20
        const val MAX_DURATION_LENGTH = 50
        const val MAX_TEXT_LENGTH = 500
        const val MAX_PROMPT_LENGTH = 1_000
        const val MAX_PROMPTS = 20
    }

    private fun DatePlanPreferenceEntity.toDomain(): DatePlanPreference = DatePlanPreference(
        id = id,
        coupleId = coupleId,
        dateIdeaId = dateIdeaId,
        preferredDate = preferredDate,
        preferredTime = preferredTime,
        budget = budget,
        duration = duration,
        createdAt = createdAt,
        updatedAt = updatedAt
    )

    private fun DatePlanPreference.toEntity(): DatePlanPreferenceEntity = DatePlanPreferenceEntity(
        id = id,
        coupleId = coupleId,
        dateIdeaId = dateIdeaId,
        preferredDate = preferredDate,
        preferredTime = preferredTime,
        budget = budget,
        duration = duration,
        createdAt = createdAt,
        updatedAt = updatedAt
    )

    private fun DatePlanEntity.toDomain(): DatePlan = DatePlan(
        id = id,
        coupleId = coupleId,
        dateIdeaId = dateIdeaId,
        scheduledDate = scheduledDate,
        scheduledTime = scheduledTime,
        budget = budget,
        duration = duration,
        status = DatePlanStatus.fromFirestoreValue(status),
        activity = activity,
        food = food,
        conversationPrompts = conversationPrompts.split(",").filter { it.isNotEmpty() },
        optionalChallenge = optionalChallenge,
        createdAt = createdAt,
        updatedAt = updatedAt
    )

    private fun DatePlan.toEntity(): DatePlanEntity = DatePlanEntity(
        id = id,
        coupleId = coupleId,
        dateIdeaId = dateIdeaId,
        scheduledDate = scheduledDate,
        scheduledTime = scheduledTime,
        budget = budget,
        duration = duration,
        status = status.toFirestoreValue(),
        activity = activity,
        food = food,
        conversationPrompts = conversationPrompts.joinToString(","),
        optionalChallenge = optionalChallenge,
        createdAt = createdAt,
        updatedAt = updatedAt
    )
}
