package com.rugvedsarika.privatelog.utils

import android.content.Context
import android.net.Uri
import com.google.gson.Gson
import com.rugvedsarika.privatelog.data.repository.NoteRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.OutputStreamWriter
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec

class BackupHelper(private val context: Context, private val repository: NoteRepository) {

    private val gson = Gson()
    private val prefs = PreferenceHelper(context)

    suspend fun backupData(uri: Uri) = withContext(Dispatchers.IO) {
        val notes = repository.getNotesList()
        val json = gson.toJson(notes)
        
        // Encryption
        val key = prefs.getOrGenerateDatabaseKey() // Refactor: should separate keys, but reuse for now
        val secretKey = SecretKeySpec(key, "AES")
        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        cipher.init(Cipher.ENCRYPT_MODE, secretKey)
        val iv = cipher.iv
        val encryptedBytes = cipher.doFinal(json.toByteArray(Charsets.UTF_8))

        context.contentResolver.openOutputStream(uri)?.use { outputStream ->
            // Write IV len (1 byte), IV, then data
            outputStream.write(iv.size)
            outputStream.write(iv)
            outputStream.write(encryptedBytes)
        }
    }

    suspend fun restoreData(uri: Uri) = withContext(Dispatchers.IO) {
        context.contentResolver.openInputStream(uri)?.use { inputStream ->
            val ivSize = inputStream.read()
            if (ivSize == -1) throw Exception("Invalid backup file")
            val iv = ByteArray(ivSize)
            inputStream.read(iv)
            
            val encryptedBytes = inputStream.readBytes()

            val key = prefs.getOrGenerateDatabaseKey()
            val secretKey = SecretKeySpec(key, "AES")
            val cipher = Cipher.getInstance("AES/GCM/NoPadding")
            val spec = GCMParameterSpec(128, iv)
            cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)

            val decryptedBytes = cipher.doFinal(encryptedBytes)
            val json = String(decryptedBytes, Charsets.UTF_8)
            
            val type = object : com.google.gson.reflect.TypeToken<List<com.rugvedsarika.privatelog.data.model.Note>>() {}.type
            val notes: List<com.rugvedsarika.privatelog.data.model.Note> = gson.fromJson(json, type)
            
            // Clear or Append? Appending is safer. Or Replace all.
            // Requirement doesn't specify. I'll insert/update.
            notes.forEach { note ->
                // note.id might conflict. If autoGenerate, we should set id=0 to insert as new?
                // Or keep original IDs? If keeping IDs, might overwrite existing notes with same ID.
                // Backup implies restore state. I'll use insert (upsert).
                repository.insert(note) 
            }
        }
    }
}
