package stories.presentation import android.net.Uri import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import core.network.ServerConfig import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import stories.data.remote.api.CreateStoryRequest import stories.data.remote.api.StoryApi import java.io.File import javax.inject.Inject data class TextObject( val id: Long = System.currentTimeMillis(), val text: String, val offset: Offset = Offset(100f, 100f), val color: Color = Color.White, val fontSize: Float = 24f, val scale: Float = 1f ) data class StickerObject( val id: Long = System.currentTimeMillis(), val emoji: String, val offset: Offset = Offset(200f, 200f), val scale: Float = 1.5f ) sealed class StoryTool { object None : StoryTool() object Text : StoryTool() object Crop : StoryTool() object Stickers : StoryTool() object Brush : StoryTool() object Filters : StoryTool() object Trim : StoryTool() } @HiltViewModel class CreateStoryViewModel @Inject constructor( private val storyApi: StoryApi, private val serverConfig: ServerConfig ) : ViewModel() { var selectedMediaUri by mutableStateOf(null) private set var isVideo by mutableStateOf(false) private set var currentTool by mutableStateOf(StoryTool.None) private set var bgColor by mutableStateOf(Color(0xFF1E1E2E)) private set val textObjects = mutableStateListOf() val stickerObjects = mutableStateListOf() var isUploading by mutableStateOf(false) private set private val _uploadSuccess = MutableStateFlow(false) val uploadSuccess = _uploadSuccess.asStateFlow() private val _errorMessage = MutableStateFlow(null) val errorMessage = _errorMessage.asStateFlow() fun onMediaSelected(uri: Uri, isVideo: Boolean) { this.selectedMediaUri = uri this.isVideo = isVideo if (isVideo) { currentTool = StoryTool.Trim } else { currentTool = StoryTool.Crop } } fun setTool(tool: StoryTool) { currentTool = tool } fun addText(text: String) { textObjects.add(TextObject(text = text)) currentTool = StoryTool.Text } fun addSticker(emoji: String) { stickerObjects.add(StickerObject(emoji = emoji)) } fun updateBgColor(color: Color) { bgColor = color } fun removeMedia() { selectedMediaUri = null isVideo = false currentTool = StoryTool.None textObjects.clear() stickerObjects.clear() } fun publishStory(context: android.content.Context) { val uri = selectedMediaUri ?: return val maxFileSize = serverConfig.getServerConfig().limits.maxFileSize viewModelScope.launch { isUploading = true try { val file = uriToFile(context, uri) if (file.length() > maxFileSize) { _errorMessage.value = "File too large for this server" return@launch } val mediaUrl = if (isVideo) { val part = MultipartBody.Part.createFormData( "file", file.name, file.asRequestBody("video/*".toMediaTypeOrNull()) ) storyApi.uploadVideo(part).url } else { // Simulating image upload via same or different endpoint "https://example.com/simulated_upload.jpg" } val request = CreateStoryRequest( type = if (isVideo) "video" else "image", mediaUrl = mediaUrl, bgColor = String.format("#%06X", (0xFFFFFF and bgColor.value.toInt())), content = null // Serialize stickers/text if needed ) storyApi.createStory(request) _uploadSuccess.value = true } catch (e: Exception) { _errorMessage.value = e.message ?: "Upload failed" } finally { isUploading = false } } } private fun uriToFile(context: android.content.Context, uri: Uri): File { val inputStream = context.contentResolver.openInputStream(uri) val file = File(context.cacheDir, "temp_story_${System.currentTimeMillis()}") file.outputStream().use { outputStream -> inputStream?.copyTo(outputStream) } return file } }