import Foundation

struct ChatMessage: Codable, Identifiable, Equatable {
    let id: String
    let from: String
    let fromName: String
    let body: String
    let sentAt: Date
    let attachment: AttachmentInfo?
    var isRead: Bool
}

struct AttachmentInfo: Codable, Equatable {
    let fileID: String
    let name: String
    let size: Int
}

actor MessageStore {
    static let shared = MessageStore()

    func save(_ message: ChatMessage) throws {
        var messages = try loadAll()

        if let index = messages.firstIndex(where: { $0.id == message.id }) {
            messages[index] = message
        } else {
            messages.append(message)
        }

        messages.sort { $0.sentAt < $1.sentAt }
        try write(messages)
    }

    func loadAll() throws -> [ChatMessage] {
        let url = try messagesURL()

        guard fileManager.fileExists(atPath: url.path) else {
            return []
        }

        let data = try Data(contentsOf: url)
        return try decoder.decode([ChatMessage].self, from: data)
            .sorted { $0.sentAt < $1.sentAt }
    }

    func markRead(id: String) throws {
        var messages = try loadAll()

        guard let index = messages.firstIndex(where: { $0.id == id }) else {
            return
        }

        messages[index].isRead = true
        try write(messages)
    }

    var unreadCount: Int {
        get async {
            (try? loadAll().filter { !$0.isRead }.count) ?? 0
        }
    }

    private let fileManager = FileManager.default
    private let encoder: JSONEncoder = {
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
        return encoder
    }()
    private let decoder: JSONDecoder = {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return decoder
    }()

    private func messagesURL() throws -> URL {
        let applicationSupportDirectory = try fileManager.url(
            for: .applicationSupportDirectory,
            in: .userDomainMask,
            appropriateFor: nil,
            create: true
        )
        let directory = applicationSupportDirectory.appendingPathComponent(
            "de.diyaa.fchati",
            isDirectory: true
        )

        try fileManager.createDirectory(at: directory, withIntermediateDirectories: true)
        return directory.appendingPathComponent("messages.json")
    }

    private func write(_ messages: [ChatMessage]) throws {
        let data = try encoder.encode(messages)
        try data.write(to: messagesURL(), options: .atomic)
    }
}
