import Foundation
import Security

final class ServerListStore {
    static let shared = ServerListStore()

    private let groupId = "group.cat.voice.VoiceCat"
    private let keychainService = "cat.voice.VoiceCatiOS"

    // MARK: - App Group Container

    var appGroupContainer: URL {
        guard let url = FileManager.default.containerURL(
            forSecurityApplicationGroupIdentifier: groupId)
        else {
            // Fall back to app-only support dir if App Groups are unavailable (e.g. simulator
            // without entitlements). TOFU pins won't be shared with the broadcast extension,
            // but connect + auth still work.
            return FileManager.default.urls(for: .applicationSupportDirectory,
                                            in: .userDomainMask).first!
        }
        return url
    }

    private var voicecatDir: URL {
        let dir = appGroupContainer.appendingPathComponent("voicecat", isDirectory: true)
        try? FileManager.default.createDirectory(at: dir,
                                                  withIntermediateDirectories: true)
        return dir
    }

    var tofuStorePath: String { voicecatDir.appendingPathComponent("tofu_pins.txt").path }

    private var serversURL: URL { voicecatDir.appendingPathComponent("servers.json") }

    // MARK: - Server list persistence

    func load() -> [SavedServer] {
        guard let data = try? Data(contentsOf: serversURL),
              let list = try? JSONDecoder().decode([SavedServer].self, from: data)
        else { return [] }
        return list
    }

    func save(_ servers: [SavedServer]) {
        guard let data = try? JSONEncoder().encode(servers) else { return }
        try? data.write(to: serversURL, options: .atomic)
    }

    // MARK: - Keychain

    func savePassword(_ password: String, tag: String) {
        let data = Data(password.utf8)
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: keychainService,
            kSecAttrAccount: tag,
            kSecAttrAccessGroup: groupId,
        ]
        SecItemDelete(query as CFDictionary)
        var add = query
        add[kSecValueData] = data
        SecItemAdd(add as CFDictionary, nil)
    }

    func loadPassword(tag: String) -> String? {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: keychainService,
            kSecAttrAccount: tag,
            kSecAttrAccessGroup: groupId,
            kSecReturnData: true,
            kSecMatchLimit: kSecMatchLimitOne,
        ]
        var result: AnyObject?
        guard SecItemCopyMatching(query as CFDictionary, &result) == errSecSuccess,
              let data = result as? Data
        else { return nil }
        return String(data: data, encoding: .utf8)
    }

    func deletePassword(tag: String) {
        let query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrService: keychainService,
            kSecAttrAccount: tag,
            kSecAttrAccessGroup: groupId,
        ]
        SecItemDelete(query as CFDictionary)
    }

}
