package com.estateunified.panel import com.google.gson.Gson import com.google.gson.reflect.TypeToken import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Path import java.util.UUID internal data class DealTimelineEntry( val status: String, val occurredAtIso: String, val note: String = "", ) internal data class DealDto( val id: String = UUID.randomUUID().toString(), val ownerUserId: String, val fixationId: String? = null, val listingId: String, val listingTitle: String = "", val leadName: String = "", val leadPhone: String = "", var status: String = "INTEREST", val timeline: MutableList = mutableListOf(), val createdAtIso: String = java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( java.time.LocalDateTime.now(), ), var updatedAtIso: String = java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( java.time.LocalDateTime.now(), ), ) internal class DealStore( private val gson: Gson, private val file: Path, ) { private val lock = Any() fun absolutePath(): String = file.toAbsolutePath().normalize().toString() fun listForUser(userId: String): List = synchronized(lock) { load().filter { it.ownerUserId == userId } } fun get(id: String): DealDto? = synchronized(lock) { load().firstOrNull { it.id == id } } fun add(dto: DealDto): DealDto = synchronized(lock) { val list = load().toMutableList() list.add(0, dto) persist(list) dto } fun setStatus( id: String, status: String, note: String = "", ): DealDto? = synchronized(lock) { val list = load().toMutableList() val idx = list.indexOfFirst { it.id == id } if (idx < 0) return@synchronized null val cur = list[idx] val now = java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( java.time.LocalDateTime.now(), ) val newTimeline = cur.timeline.toMutableList() newTimeline.add(0, DealTimelineEntry(status = status, occurredAtIso = now, note = note)) val updated = cur.copy( status = status, updatedAtIso = now, timeline = newTimeline, ) list[idx] = updated persist(list) updated } private fun load(): List { if (!Files.isRegularFile(file)) return emptyList() val text = Files.readString(file, StandardCharsets.UTF_8) if (text.isBlank()) return emptyList() return runCatching { gson.fromJson>(text, listType) ?: emptyList() } .getOrElse { emptyList() } } private fun persist(list: List) { Files.createDirectories(file.toAbsolutePath().parent) Files.writeString(file, gson.toJson(list), StandardCharsets.UTF_8) } companion object { private val listType = object : TypeToken>() {}.type } }