Pith - wedge
package com.vgmlr.wedge

import android.content.Context
import androidx.room.*
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import androidx.compose.ui.graphics.Color
import androidx.core.graphics.toColorInt

@Entity(tableName = "notes")
data class NoteEntity(
    @PrimaryKey val id: Int = 1,
    val content: String = "",
    val lastModified: Long = System.currentTimeMillis()
)

@Dao
interface NoteDao {
    @Query("SELECT * FROM notes WHERE id = 1")
    fun getNote(): Flow<NoteEntity?>

    @Query("SELECT * FROM notes WHERE id = 1")
    suspend fun getNoteSync(): NoteEntity?

    @Query("UPDATE notes SET content = :content WHERE id = 1")
    suspend fun updateContentPreservingTimestamp(content: String)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun save(note: NoteEntity)
}

@Database(entities = [NoteEntity::class], version = 3, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao
    companion object {
        @Volatile private var INSTANCE: AppDatabase? = null
        fun getInstance(context: Context): AppDatabase = INSTANCE ?: synchronized(this) {
            val instance = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "wedge_db")
                .fallbackToDestructiveMigration()
                .build()
            INSTANCE = instance
            instance
        }
    }
}

private val Context.dataStore by preferencesDataStore("settings")

data class SettingsState(
    val textColor: String = WedgeConfig.TEXT_COLOR_DEFAULT,
    val bgColor: String = WedgeConfig.BG_COLOR_DEFAULT,
    val widgetTextColor: String = WedgeConfig.WIDGET_TEXT_COLOR_DEFAULT,
    val widgetBgColor: String = WedgeConfig.WIDGET_BG_COLOR_DEFAULT,
    val editorFontSize: Float = WedgeConfig.FONT_SIZE_DEFAULT,
    val widgetFontSize: Float = WedgeConfig.WIDGET_FONT_SIZE_DEFAULT,
    val lineHeight: Float = WedgeConfig.LINE_HEIGHT_DEFAULT,
    val boldColor: String = WedgeConfig.BOLD_COLOR_DEFAULT,
    val incognitoMode: Boolean = false,
    val passKey: String = "wedge03569"
)

data class PhraseSpec(
    val words: Boolean = WedgeConfig.PHRASE_WORDS_DEFAULT,
    val wordCount: Int = WedgeConfig.PHRASE_WORD_COUNT_DEFAULT,
    val letters: Int = WedgeConfig.PHRASE_LETTERS_DEFAULT,
    val numbers: Boolean = WedgeConfig.PHRASE_NUMBERS_DEFAULT,
    val numberCount: Int = WedgeConfig.PHRASE_NUMBER_COUNT_DEFAULT
)

class PreferenceManager(private val context: Context) {
    private val keyTextCol = stringPreferencesKey("text_color")
    private val keyBgCol = stringPreferencesKey("bg_color")
    private val keyWTextCol = stringPreferencesKey("widget_text_color")
    private val keyWBgCol = stringPreferencesKey("widget_bg_color")
    private val keyBoldCol = stringPreferencesKey("bold_color")
    private val keyLinkCol = stringPreferencesKey("link_color")
    private val keyLinkEnabled = booleanPreferencesKey("link_enabled")
    private val keyIncognito = booleanPreferencesKey("incognito_mode")
    private val keyGuideEnabled = booleanPreferencesKey("guide_enabled")
    private val keyGuideChars = intPreferencesKey("guide_chars")
    private val keyGuideOpacity = intPreferencesKey("guide_opacity")
    private val keyBtnPadRight = intPreferencesKey("btn_pad_right")
    private val keyBtnPadBottom = intPreferencesKey("btn_pad_bottom")
    private val keyEditorPadLeft = intPreferencesKey("editor_pad_left")
    private val keyESize = floatPreferencesKey("editor_font_size_abs")
    private val keyWSize = floatPreferencesKey("widget_font_size_abs")
    private val keyWidgetBoldCol = stringPreferencesKey("widget_bold_color")
    private val keyNextTimeBg = stringPreferencesKey("next_time_bg_color")
    private val keyWidgetNextTimeBg = stringPreferencesKey("widget_next_time_bg_color")
    private val keyLHeight = floatPreferencesKey("line_height_multiplier")
    private val keyHeaderFormat = stringPreferencesKey("header_format")
    private val keyPruneDays = booleanPreferencesKey("prune_days")
    private val keyAlarmSoundUri = stringPreferencesKey("alarm_sound_uri")
    private val keyAlarmDurationMinutes = intPreferencesKey("alarm_duration_minutes")
    private val keyVibrationEnabled = booleanPreferencesKey("vibration_enabled")
    private val keyPassKey = stringPreferencesKey("pass_key")
    private val keyBackupInterval = intPreferencesKey("backup_interval_minutes")
    private val keyBackupLocation = stringPreferencesKey("backup_location_uri")
    private val keyBackupStamp = longPreferencesKey("backup_last_stamp")
    private val keyPhraseWords = booleanPreferencesKey("phrase_words")
    private val keyPhraseWordCount = intPreferencesKey("phrase_word_count")
    private val keyPhraseLetters = intPreferencesKey("phrase_letters")
    private val keyPhraseNumbers = booleanPreferencesKey("phrase_numbers")
    private val keyPhraseNumberCount = intPreferencesKey("phrase_number_count")
    // legacy keys
    private val legacyBackupEncrypt = booleanPreferencesKey("backup_encrypt")
    private val legacyBackupPhrase = stringPreferencesKey("backup_phrase")
    private val legacyBtnRadius = intPreferencesKey("btn_radius")
    private val legacyTopBarBtnLeft = booleanPreferencesKey("top_bar_btn_left")

    val settings: Flow<SettingsState> = context.dataStore.data.map { prefs ->
        SettingsState(
            textColor = prefs[keyTextCol] ?: WedgeConfig.TEXT_COLOR_DEFAULT,
            bgColor = prefs[keyBgCol] ?: WedgeConfig.BG_COLOR_DEFAULT,
            widgetTextColor = prefs[keyWTextCol] ?: WedgeConfig.WIDGET_TEXT_COLOR_DEFAULT,
            widgetBgColor = prefs[keyWBgCol] ?: WedgeConfig.WIDGET_BG_COLOR_DEFAULT,
            editorFontSize = prefs[keyESize] ?: WedgeConfig.FONT_SIZE_DEFAULT,
            widgetFontSize = prefs[keyWSize] ?: WedgeConfig.WIDGET_FONT_SIZE_DEFAULT,
            lineHeight = prefs[keyLHeight] ?: WedgeConfig.LINE_HEIGHT_DEFAULT,
            boldColor = prefs[keyBoldCol] ?: WedgeConfig.BOLD_COLOR_DEFAULT,
            incognitoMode = prefs[keyIncognito] ?: false,
            passKey = prefs[keyPassKey] ?: "wedge03569"
        )
    }

    val textColor: Flow<String> =
        context.dataStore.data.map { it[keyTextCol] ?: WedgeConfig.TEXT_COLOR_DEFAULT }
    val bgColor: Flow<String> =
        context.dataStore.data.map { it[keyBgCol] ?: WedgeConfig.BG_COLOR_DEFAULT }
    val widgetTextColor: Flow<String> =
        context.dataStore.data.map { it[keyWTextCol] ?: WedgeConfig.WIDGET_TEXT_COLOR_DEFAULT }
    val widgetBgColor: Flow<String> =
        context.dataStore.data.map { it[keyWBgCol] ?: WedgeConfig.WIDGET_BG_COLOR_DEFAULT }
    val boldColor: Flow<String> =
        context.dataStore.data.map { it[keyBoldCol] ?: WedgeConfig.BOLD_COLOR_DEFAULT }
    val linkColor: Flow<String> =
        context.dataStore.data.map { it[keyLinkCol] ?: WedgeConfig.LINK_COLOR_DEFAULT }
    val linkEnabled: Flow<Boolean> = context.dataStore.data.map { it[keyLinkEnabled] ?: false }
    val incognitoMode: Flow<Boolean> = context.dataStore.data.map { it[keyIncognito] ?: false }
    val guideEnabled: Flow<Boolean> =
        context.dataStore.data.map { it[keyGuideEnabled] ?: WedgeConfig.GUIDE_ENABLED_DEFAULT }
    val guideChars: Flow<Int> =
        context.dataStore.data.map { it[keyGuideChars] ?: WedgeConfig.GUIDE_CHARS_DEFAULT }
    val guideOpacity: Flow<Int> =
        context.dataStore.data.map { it[keyGuideOpacity] ?: WedgeConfig.GUIDE_OPACITY_DEFAULT }
    val btnPadRight: Flow<Int> =
        context.dataStore.data.map { it[keyBtnPadRight] ?: WedgeConfig.BTN_PAD_RIGHT_DEFAULT }
    val btnPadBottom: Flow<Int> =
        context.dataStore.data.map { it[keyBtnPadBottom] ?: WedgeConfig.BTN_PAD_BOTTOM_DEFAULT }
    val editorPadLeft: Flow<Int> =
        context.dataStore.data.map { it[keyEditorPadLeft] ?: WedgeConfig.EDITOR_PAD_LEFT_DEFAULT }
    val widgetBoldColor: Flow<String> =
        context.dataStore.data.map { it[keyWidgetBoldCol] ?: WedgeConfig.WIDGET_BOLD_COLOR_DEFAULT }
    val nextTimeBg: Flow<String> =
        context.dataStore.data.map { it[keyNextTimeBg] ?: WedgeConfig.CALENDAR_COLOR_DEFAULT }
    val widgetNextTimeBg: Flow<String> = context.dataStore.data.map {
        it[keyWidgetNextTimeBg] ?: WedgeConfig.WIDGET_CALENDAR_COLOR_DEFAULT
    }
    val editorFontSize: Flow<Float> =
        context.dataStore.data.map { it[keyESize] ?: WedgeConfig.FONT_SIZE_DEFAULT }
    val widgetFontSize: Flow<Float> =
        context.dataStore.data.map { it[keyWSize] ?: WedgeConfig.FONT_SIZE_DEFAULT }
    val lineHeight: Flow<Float> =
        context.dataStore.data.map { it[keyLHeight] ?: WedgeConfig.LINE_HEIGHT_DEFAULT }
    val headerFormat: Flow<String> =
        context.dataStore.data.map { it[keyHeaderFormat] ?: WedgeConfig.HEADER_FORMAT_DEFAULT }
    val autoPrune: Flow<Boolean> =
        context.dataStore.data.map { it[keyPruneDays] ?: WedgeConfig.PRUNE_DAYS_DEFAULT }
    val alarmSoundUri: Flow<String> = context.dataStore.data.map { it[keyAlarmSoundUri] ?: "" }
    val alarmDurationMinutes: Flow<Int> =
        context.dataStore.data.map { it[keyAlarmDurationMinutes] ?: 5 }
    val vibrationEnabled: Flow<Boolean> = 
        context.dataStore.data.map { it[keyVibrationEnabled] ?: false }
    val passKey: Flow<String> = context.dataStore.data.map { it[keyPassKey] ?: "wedge03569" }
    
    val backupInterval: Flow<Int> =
        context.dataStore.data.map { it[keyBackupInterval] ?: WedgeConfig.BACKUP_INTERVAL_DEFAULT }
    val backupLocation: Flow<String> = context.dataStore.data.map { it[keyBackupLocation] ?: "" }
    val backupStamp: Flow<Long> = context.dataStore.data.map { it[keyBackupStamp] ?: 0L }
    val phraseSpec: Flow<PhraseSpec> = context.dataStore.data.map {
        PhraseSpec(
            words = it[keyPhraseWords] ?: WedgeConfig.PHRASE_WORDS_DEFAULT,
            wordCount = it[keyPhraseWordCount] ?: WedgeConfig.PHRASE_WORD_COUNT_DEFAULT,
            letters = it[keyPhraseLetters] ?: WedgeConfig.PHRASE_LETTERS_DEFAULT,
            numbers = it[keyPhraseNumbers] ?: WedgeConfig.PHRASE_NUMBERS_DEFAULT,
            numberCount = it[keyPhraseNumberCount] ?: WedgeConfig.PHRASE_NUMBER_COUNT_DEFAULT
        )
    }

    suspend fun setColors(
        txt: String,
        bg: String,
        wtxt: String,
        wbg: String,
        bcol: String,
        wBcol: String,
        nextBg: String,
        wNextBg: String
    ) = context.dataStore.edit {
        it[keyTextCol] = txt; it[keyBgCol] = bg; it[keyWTextCol] = wtxt; it[keyWBgCol] =
        wbg; it[keyBoldCol] = bcol
        it[keyWidgetBoldCol] = wBcol; it[keyNextTimeBg] = nextBg; it[keyWidgetNextTimeBg] = wNextBg
    }

    suspend fun setLinkColor(link: String) = context.dataStore.edit {
        it[keyLinkCol] = link
    }

    suspend fun setLinkEnabled(enabled: Boolean) = context.dataStore.edit {
        it[keyLinkEnabled] = enabled
    }

    suspend fun setFontSettings(eSize: Float, wSize: Float, lHeight: Float) =
        context.dataStore.edit {
            it[keyESize] = eSize; it[keyWSize] = wSize; it[keyLHeight] = lHeight
        }

    suspend fun setIncognito(incognito: Boolean) = context.dataStore.edit {
        it[keyIncognito] = incognito
    }

    suspend fun setGuide(enabled: Boolean, chars: Int, opacity: Int) = context.dataStore.edit {
        it[keyGuideEnabled] = enabled
        it[keyGuideChars] = chars
        it[keyGuideOpacity] = opacity
    }

    suspend fun setBtnPad(right: Int, bottom: Int) = context.dataStore.edit {
        it[keyBtnPadRight] = right
        it[keyBtnPadBottom] = bottom
    }

    suspend fun setEditorPadLeft(v: Int) = context.dataStore.edit {
        it[keyEditorPadLeft] = v
    }

    suspend fun setHeaderFormat(fmt: String) = context.dataStore.edit {
        it[keyHeaderFormat] = fmt
    }

    suspend fun setAutoPrune(on: Boolean) = context.dataStore.edit {
        it[keyPruneDays] = on
    }

    suspend fun setAlarmSettings(uri: String, duration: Int, vibration: Boolean) = context.dataStore.edit {
        it[keyAlarmSoundUri] = uri
        it[keyAlarmDurationMinutes] = duration
        it[keyVibrationEnabled] = vibration
    }
    
    suspend fun setPassKey(newPassKey: String) = context.dataStore.edit {
        it[keyPassKey] = newPassKey
    }

    suspend fun setBackupSettings(interval: Int, location: String) = context.dataStore.edit {
        it[keyBackupInterval] = interval
        it[keyBackupLocation] = location
    }

    suspend fun setBackupStamp(stamp: Long) = context.dataStore.edit {
        it[keyBackupStamp] = stamp
    }

    suspend fun setPhraseSpec(spec: PhraseSpec) = context.dataStore.edit {
        it[keyPhraseWords] = spec.words
        it[keyPhraseWordCount] = spec.wordCount
        it[keyPhraseLetters] = spec.letters
        it[keyPhraseNumbers] = spec.numbers
        it[keyPhraseNumberCount] = spec.numberCount
    }

    // wipe legacy
    suspend fun purgeLegacy() = context.dataStore.edit {
        it.remove(legacyBackupEncrypt)
        it.remove(legacyBackupPhrase)
        it.remove(legacyBtnRadius)
        it.remove(legacyTopBarBtnLeft)
    }
}

fun parseColor(hex: String): Color {
    return try { Color(hex.toColorInt()) } catch (_: Exception) { if (hex.length > 7) Color.White else Color.Black }
}