package com.example.shiftalarm

import android.content.Context
import android.net.Uri
import org.json.JSONArray
import org.json.JSONObject
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * Handles data backup and restoration (Database + SharedPreferences).
 * Format: JSON
 */
object BackupManager {

    suspend fun backupData(context: Context, uri: Uri, dao: ShiftDao) = withContext(Dispatchers.IO) {
        val overrides = dao.getAllOverrides()
        val memos = dao.getAllMemos()

        val json = JSONObject()
        
        // 1. Backup Overrides
        val overrideArray = JSONArray()
        overrides.forEach { 
            overrideArray.put(JSONObject().apply {
                put("date", it.date)
                put("shift", it.shift)
                put("team", it.team)
                put("factory", it.factory)
            })
        }
        json.put("overrides", overrideArray)

        // 1.5 Backup Custom Alarms
        val customAlarms = dao.getAllCustomAlarms()
        val customAlarmArray = JSONArray()
        customAlarms.forEach {
            customAlarmArray.put(JSONObject().apply {
                put("time", it.time)
                put("shiftType", it.shiftType)
                put("isEnabled", it.isEnabled)
                put("soundUri", it.soundUri)
                put("snoozeInterval", it.snoozeInterval)
                put("snoozeRepeat", it.snoozeRepeat)
            })
        }
        json.put("custom_alarms_v2", customAlarmArray)

        // 2. Backup Memos
        val memoArray = JSONArray()
        memos.forEach {
            memoArray.put(JSONObject().apply {
                put("date", it.date)
                put("content", it.content)
            })
        }
        json.put("memos", memoArray)
        
        // 3. Backup Settings (SharedPreferences)
        val prefs = context.getSharedPreferences("ShiftAlarmPrefs", Context.MODE_PRIVATE)
        val settings = JSONObject()
        prefs.all.forEach { (key, value) ->
            if (value is String) settings.put(key, value)
            else if (value is Boolean) settings.put(key, value)
            else if (value is Int) settings.put(key, value)
            else if (value is Float) settings.put(key, value.toDouble())
            else if (value is Long) settings.put(key, value)
            else if (value is Double) settings.put(key, value)
        }
        json.put("settings", settings)
        
        json.put("magic", "SHIFTRING_BACKUP_V3")
        json.put("timestamp", System.currentTimeMillis())

        val finalString = json.toString()
        val encodedBytes = android.util.Base64.encode(finalString.toByteArray(), android.util.Base64.DEFAULT)

        context.contentResolver.openOutputStream(uri)?.use { os ->
            os.write(encodedBytes)
        }
    }

    suspend fun restoreData(context: Context, uri: Uri, dao: ShiftDao) = withContext(Dispatchers.IO) {
        val bytes = context.contentResolver.openInputStream(uri)?.use { 
            it.readBytes()
        } ?: throw Exception("Failed to read file")
        
        var content = ""
        try {
            // Try Base64 first (V3)
            val decodedBytes = android.util.Base64.decode(bytes, android.util.Base64.DEFAULT)
            content = String(decodedBytes)
        } catch (e: Exception) {
            // Fallback to plain text (V1/V2)
            content = String(bytes)
        }
        
        val json = JSONObject(content)
        
        val magic = json.optString("magic", "")
        if (magic != "SHIFTRING_BACKUP_V1" && magic != "SHIFTRING_BACKUP_V2" && magic != "SHIFTRING_BACKUP_V3") {
            throw Exception("올바르지 않은 백업 파일 형식입니다.")
        }

        // 1. Restore Settings FIRST
        if (json.has("settings")) {
            val settings = json.getJSONObject("settings")
            val prefs = context.getSharedPreferences("ShiftAlarmPrefs", Context.MODE_PRIVATE).edit()
            prefs.clear() 
            val keys = settings.keys()
            while(keys.hasNext()) {
                val key = keys.next()
                if (settings.isNull(key)) continue
                
                val value = settings.get(key)
                when(value) {
                    is Boolean -> prefs.putBoolean(key, value)
                    is Int -> prefs.putInt(key, value)
                    is String -> prefs.putString(key, value)
                    is Double -> prefs.putFloat(key, value.toFloat())
                    is Long -> prefs.putLong(key, value)
                }
            }
            prefs.apply()
        }
        
        val restoredPrefs = context.getSharedPreferences("ShiftAlarmPrefs", Context.MODE_PRIVATE)
        val fallbackFactory = restoredPrefs.getString("selected_factory", "Jeonju") ?: "Jeonju"
        val fallbackTeam = restoredPrefs.getString("selected_team", "A") ?: "A"
        
        // 2. Restore Overrides
        if (json.has("overrides")) {
            dao.clearOverrides()
            val arr = json.getJSONArray("overrides")
            for (i in 0 until arr.length()) {
                val obj = arr.getJSONObject(i)
                dao.insertOverride(ShiftOverride(
                    factory = obj.optString("factory", fallbackFactory),
                    team = obj.optString("team", fallbackTeam),
                    date = obj.getString("date"),
                    shift = obj.getString("shift")
                ))
            }
        }

        // 2.5 Restore Custom Alarms
        if (json.has("custom_alarms_v2")) {
            dao.clearCustomAlarms()
            val arr = json.getJSONArray("custom_alarms_v2")
            for (i in 0 until arr.length()) {
                val obj = arr.getJSONObject(i)
                dao.insertCustomAlarm(CustomAlarm(
                    time = obj.getString("time"),
                    shiftType = obj.getString("shiftType"),
                    isEnabled = obj.optBoolean("isEnabled", true),
                    soundUri = obj.optString("soundUri", null),
                    snoozeInterval = obj.optInt("snoozeInterval", 5),
                    snoozeRepeat = obj.optInt("snoozeRepeat", 3)
                ))
            }
        }
        
        // 3. Restore Memos
        if (json.has("memos")) {
            dao.clearMemos()
            val arr = json.getJSONArray("memos")
            for (i in 0 until arr.length()) {
                val obj = arr.getJSONObject(i)
                dao.insertMemo(DailyMemo(
                    obj.getString("date"),
                    obj.getString("content")
                ))
            }
        }
    }
}
