import Foundation
import GRDB
import Martin

struct RosterVersion: DBStorable {
    static let databaseTableName = "rosterVersions"

    var bareJid: String
    var version: String
    var id: String { bareJid }
}

struct Roster: DBStorable {
    static let databaseTableName = "rosters"

    var bareJid: String = ""
    var contactBareJid: String
    var name: String?
    var subscription: String
    var ask: Bool
    var data: DBRosterData
    var locallyDeleted: Bool = false

    var id: String { "\(bareJid)-\(contactBareJid)" }
}

struct DBRosterData: Codable, DatabaseValueConvertible {
    let groups: [String]
    let annotations: [RosterItemAnnotation]

    public var databaseValue: DatabaseValue {
        let encoder = JSONEncoder()
        // swiftlint:disable:next force_try
        let data = try! encoder.encode(self)
        return data.databaseValue
    }

    public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? {
        guard let data = Data.fromDatabaseValue(dbValue) else {
            return nil
        }
        let decoder = JSONDecoder()
        // swiftlint:disable:next force_try
        return try! decoder.decode(Self.self, from: data)
    }

    static func == (lhs: DBRosterData, rhs: DBRosterData) -> Bool {
        lhs.groups == rhs.groups && lhs.annotations == rhs.annotations
    }
}

extension RosterItemAnnotation: Equatable {
    public static func == (lhs: RosterItemAnnotation, rhs: RosterItemAnnotation) -> Bool {
        lhs.type == rhs.type && lhs.values == rhs.values
    }
}

extension Roster: Equatable {
    static func == (lhs: Roster, rhs: Roster) -> Bool {
        lhs.bareJid == rhs.bareJid && lhs.contactBareJid == rhs.contactBareJid
    }
}