package com.recordatorios.app

import java.util.Calendar

data class ParsedVoiceNote(
    val title: String,
    val content: String,
    val reminderDate: Long?,
    val categoryName: String? = null,
    val recurrence: RecurrenceType = RecurrenceType.NONE
)

object VoiceNoteParser {

    private val numberWords = mapOf(
        "uno" to 1, "una" to 1,
        "dos" to 2,
        "tres" to 3,
        "cuatro" to 4,
        "cinco" to 5,
        "seis" to 6,
        "siete" to 7,
        "ocho" to 8,
        "nueve" to 9,
        "diez" to 10,
        "once" to 11,
        "doce" to 12,
        "trece" to 13,
        "catorce" to 14,
        "quince" to 15,
        "dieciseis" to 16, "dieciséis" to 16,
        "diecisiete" to 17,
        "dieciocho" to 18,
        "diecinueve" to 19,
        "veinte" to 20,
        "veintiuno" to 21, "veintiuna" to 21,
        "veintidos" to 22, "veintidós" to 22,
        "veintitres" to 23, "veintitrés" to 23,
        "veinticuatro" to 24
    )

    private val monthNames = mapOf(
        "enero" to 0, "febrero" to 1, "marzo" to 2, "abril" to 3,
        "mayo" to 4, "junio" to 5, "julio" to 6, "agosto" to 7,
        "septiembre" to 8, "octubre" to 9, "noviembre" to 10, "diciembre" to 11,
        "ener" to 0, "febr" to 1, "marz" to 2, "abr" to 3,
        "may" to 4, "jun" to 5, "jul" to 6, "ago" to 7,
        "sept" to 8, "oct" to 9, "nov" to 10, "dic" to 11
    )

    private val dayNames = mapOf(
        "domingo" to Calendar.SUNDAY, "dom" to Calendar.SUNDAY,
        "lunes" to Calendar.MONDAY, "lun" to Calendar.MONDAY,
        "martes" to Calendar.TUESDAY, "mar" to Calendar.TUESDAY,
        "miercoles" to Calendar.WEDNESDAY, "mie" to Calendar.WEDNESDAY,
        "jueves" to Calendar.THURSDAY, "jue" to Calendar.THURSDAY,
        "viernes" to Calendar.FRIDAY, "vie" to Calendar.FRIDAY,
        "sabado" to Calendar.SATURDAY, "sab" to Calendar.SATURDAY,
        "sábado" to Calendar.SATURDAY
    )

    fun parse(text: String, availableCategories: List<String> = emptyList()): ParsedVoiceNote {
        val lower = text.lowercase().trim()
        val now = Calendar.getInstance()
        var reminderDate: Long? = null
        var datePhrase = ""
        var timePhrase = ""
        var cleanedText = lower
        var categoryName: String? = null
        var recurrence: RecurrenceType = RecurrenceType.NONE

        val categoryResult = extractCategory(lower, availableCategories)
        if (categoryResult != null) {
            categoryName = categoryResult.name
            cleanedText = cleanedText.replace(categoryResult.phrase, "").trim()
        }

        val recurrenceResult = extractRecurrence(lower)
        if (recurrenceResult != null) {
            recurrence = recurrenceResult.type
            cleanedText = cleanedText.replace(recurrenceResult.phrase, "").trim()
        }

        val timeResult = extractTime(lower)
        if (timeResult != null) {
            timePhrase = timeResult.phrase
            cleanedText = cleanedText.replace(timePhrase, "").trim()
        }

        val dateResult = extractDate(cleanedText, timeResult?.millis)
        if (dateResult != null) {
            datePhrase = dateResult.phrase
            cleanedText = cleanedText.replace(datePhrase, "").trim()
            reminderDate = dateResult.millis
        } else if (timeResult != null) {
            val cal = Calendar.getInstance().apply { timeInMillis = timeResult.millis }
            if (cal.after(now)) {
                reminderDate = cal.timeInMillis
            } else {
                cal.add(Calendar.DAY_OF_YEAR, 1)
                reminderDate = cal.timeInMillis
            }
        }

        val title = buildTitle(cleanedText, text)
        val content = text.trim()

        return ParsedVoiceNote(
            title = title,
            content = content,
            reminderDate = reminderDate,
            categoryName = categoryName,
            recurrence = recurrence
        )
    }

    private fun buildTitle(cleanedText: String, originalText: String): String {
        val words = cleanedText.split(Regex("\\s+")).filter { it.isNotBlank() }
        val titleWords = words.take(8)
        if (titleWords.isEmpty()) {
            val origWords = originalText.trim().split(Regex("\\s+")).filter { it.isNotBlank() }
            return origWords.take(8).joinToString(" ").replaceFirstChar { it.uppercase() }
                .take(50)
        }
        return titleWords.joinToString(" ").replaceFirstChar { it.uppercase() }.take(50)
    }

    private data class TimeInfo(val phrase: String, val millis: Long)

    private fun extractTime(text: String): TimeInfo? {
        val patterns = listOf(
            Regex("a las? (\\d{1,2})(?::(\\d{2}))?\\s*(de la manana|de la mañana|de la tarde|de la noche)?", RegexOption.IGNORE_CASE),
            Regex("a las? (\\d{1,2})\\s*(de la manana|de la mañana|de la tarde|de la noche)?", RegexOption.IGNORE_CASE),
            Regex("(\\d{1,2})(?::(\\d{2}))?\\s*(de la manana|de la mañana|de la tarde|de la noche)?", RegexOption.IGNORE_CASE),
            Regex("a las? (${numberWords.keys.joinToString("|")})\\s*(de la manana|de la mañana|de la tarde|de la noche)?", RegexOption.IGNORE_CASE),
            Regex("a las? (${numberWords.keys.joinToString("|")}) y (\\d{1,2})\\s*(de la manana|de la mañana|de la tarde|de la noche)?", RegexOption.IGNORE_CASE)
        )

        for (pattern in patterns) {
            val match = pattern.find(text) ?: continue
            
            var hour = match.groupValues[1].toIntOrNull()
            if (hour == null) {
                hour = numberWords[match.groupValues[1].lowercase()]
            }
            if (hour == null) continue
            
            val minute = match.groupValues.getOrElse(2) { "" }.toIntOrNull() ?: 0
            val period = match.groupValues.drop(2).find { it.isNotEmpty() }?.lowercase() ?: ""

            var finalHour = hour
            if (period.contains("tarde") && hour < 12) finalHour = hour + 12
            if (period.contains("noche") && hour < 12) finalHour = hour + 12
            if (period.contains("mañana") && hour == 12) finalHour = 0
            if (period.contains("manana") && hour == 12) finalHour = 0

            val cal = Calendar.getInstance().apply {
                set(Calendar.HOUR_OF_DAY, finalHour)
                set(Calendar.MINUTE, minute)
                set(Calendar.SECOND, 0)
                set(Calendar.MILLISECOND, 0)
            }

            return TimeInfo(match.value, cal.timeInMillis)
        }
        return null
    }

    private data class DateInfo(val phrase: String, val millis: Long)

    private fun extractDate(text: String, timeMillis: Long?): DateInfo? {
        val now = Calendar.getInstance()
        val baseTime = timeMillis ?: now.timeInMillis
        val baseCal = Calendar.getInstance().apply { timeInMillis = baseTime }
        val baseHour = baseCal.get(Calendar.HOUR_OF_DAY)
        val baseMinute = baseCal.get(Calendar.MINUTE)

        val relativePatterns = listOf(
            "pasado manana" to 2,
            "pasado mañana" to 2,
            "manana" to 1,
            "mañana" to 1,
            "hoy" to 0
        )

        for ((phrase, days) in relativePatterns) {
            if (text.contains(phrase, ignoreCase = true)) {
                val cal = Calendar.getInstance().apply { timeInMillis = baseTime }
                cal.add(Calendar.DAY_OF_YEAR, days)
                cal.set(Calendar.HOUR_OF_DAY, baseHour)
                cal.set(Calendar.MINUTE, baseMinute)
                return DateInfo(phrase, cal.timeInMillis)
            }
        }

        val dayMonthPattern = Regex("""(el\s+)?(\d{1,2})\s*(de)?\s*(${monthNames.keys.joinToString("|")})""", RegexOption.IGNORE_CASE)
        val dayMonthMatch = dayMonthPattern.find(text)
        if (dayMonthMatch != null) {
            val day = dayMonthMatch.groupValues[2].toIntOrNull() ?: return null
            val monthName = dayMonthMatch.groupValues[3].lowercase()
            val month = monthNames[monthName] ?: return null
            val cal = Calendar.getInstance().apply { 
                timeInMillis = baseTime
                set(Calendar.DAY_OF_MONTH, day)
                set(Calendar.MONTH, month)
                set(Calendar.HOUR_OF_DAY, baseHour)
                set(Calendar.MINUTE, baseMinute)
            }
            if (cal.before(Calendar.getInstance())) {
                cal.add(Calendar.YEAR, 1)
            }
            return DateInfo(dayMonthMatch.value, cal.timeInMillis)
        }

        val dayOfWeekPattern = Regex("""(el\s+)?(${dayNames.keys.joinToString("|")})\s*(que viene|próximo|próxima|proximo|proxima)?""", RegexOption.IGNORE_CASE)
        val dayOfWeekMatch = dayOfWeekPattern.find(text)
        if (dayOfWeekMatch != null) {
            val dayName = dayOfWeekMatch.groupValues[2].lowercase()
            val targetDay = dayNames[dayName] ?: return null
            val cal = Calendar.getInstance().apply {
                timeInMillis = baseTime
                val currentDay = get(Calendar.DAY_OF_WEEK)
                var diff = targetDay - currentDay
                if (diff <= 0) diff += 7
                add(Calendar.DAY_OF_YEAR, diff)
                set(Calendar.HOUR_OF_DAY, baseHour)
                set(Calendar.MINUTE, baseMinute)
            }
            return DateInfo(dayOfWeekMatch.value, cal.timeInMillis)
        }

        return null
    }

    private data class RecurrenceInfo(val phrase: String, val type: RecurrenceType)

    private fun extractRecurrence(text: String): RecurrenceInfo? {
        // Patrones para repetición
        val patterns = listOf(
            // Diaria
            Regex("""repetir\s+diariamente""", RegexOption.IGNORE_CASE) to RecurrenceType.DAILY,
            Regex("""todos?\s+los?\s*d[ií]as""", RegexOption.IGNORE_CASE) to RecurrenceType.DAILY,
            Regex("""cada\s+d[ií]a""", RegexOption.IGNORE_CASE) to RecurrenceType.DAILY,
            Regex("""diariamente""", RegexOption.IGNORE_CASE) to RecurrenceType.DAILY,
            
            // Semanal
            Regex("""repetir\s+semanalmente""", RegexOption.IGNORE_CASE) to RecurrenceType.WEEKLY,
            Regex("""todas?\s+las?\s*semanas""", RegexOption.IGNORE_CASE) to RecurrenceType.WEEKLY,
            Regex("""cada\s+semana""", RegexOption.IGNORE_CASE) to RecurrenceType.WEEKLY,
            Regex("""semanalmente""", RegexOption.IGNORE_CASE) to RecurrenceType.WEEKLY,
            
            // Mensual
            Regex("""repetir\s+mensualmente""", RegexOption.IGNORE_CASE) to RecurrenceType.MONTHLY,
            Regex("""todos?\s+los?\s*meses""", RegexOption.IGNORE_CASE) to RecurrenceType.MONTHLY,
            Regex("""cada\s+mes""", RegexOption.IGNORE_CASE) to RecurrenceType.MONTHLY,
            Regex("""mensualmente""", RegexOption.IGNORE_CASE) to RecurrenceType.MONTHLY,
            
            // Anual
            Regex("""repetir\s+anualmente""", RegexOption.IGNORE_CASE) to RecurrenceType.YEARLY,
            Regex("""todos?\s+los?\s*a[nñ]os""", RegexOption.IGNORE_CASE) to RecurrenceType.YEARLY,
            Regex("""cada\s+a[nñ]o""", RegexOption.IGNORE_CASE) to RecurrenceType.YEARLY,
            Regex("""anualmente""", RegexOption.IGNORE_CASE) to RecurrenceType.YEARLY
        )

        for ((pattern, type) in patterns) {
            val match = pattern.find(text)
            if (match != null) {
                return RecurrenceInfo(match.value, type)
            }
        }

        return null
    }

    private data class CategoryInfo(val phrase: String, val name: String)

    private fun extractCategory(text: String, availableCategories: List<String>): CategoryInfo? {
        // Patron 1: "categoria personal", "categoría trabajo" (espacio simple)
        // Patron 2: "categoria: personal", "categoría: trabajo" (con dos puntos)
        // Patron 3: "categoria - personal", "categoría - trabajo" (con guion)
        val categoryPattern = Regex("""categor(?:ia|ía)\s*[:\-]?\s*([a-zA-ZáéíóúñÁÉÍÓÚÑ]+(?:\s+[a-zA-ZáéíóúñÁÉÍÓÚÑ]+)*)""", RegexOption.IGNORE_CASE)
        val match = categoryPattern.find(text)
        if (match != null) {
            val capturedName = match.groupValues[1].trim().lowercase()
            // Buscar coincidencia exacta con las categorias disponibles
            val matchingCategory = availableCategories.find { 
                it.lowercase() == capturedName 
            }
            if (matchingCategory != null) {
                return CategoryInfo(match.value, matchingCategory)
            }
        }
        return null
    }
}
