import Foundation
import Security

public enum NewNoteAction: String, Codable, CaseIterable {
    case clipboard
    case editor
}

public struct SyncConfig: Codable, Equatable {
    public var serverURL: String
    public var apiToken: String?
    public var syncFolder: String?
    public var defaultUploadFolder: String?
    public var newNoteAction: NewNoteAction?
    public var autoSync: Bool
    public var syncInterval: Int // seconds
    public var deviceId: String
    public var iconName: String // SF Symbol name
    
    public static let iconOptions = [
        "tray.circle.fill",
        "arrow.triangle.2.circlepath",
        "arrow.up.doc",
        "doc.badge.arrow.up",
        "arrow.up.and.down.and.arrow.left.and.right",
        "cloud",
        "externaldrive.connected.to.line.below",
        "note.text",
        "doc.text",
        "arrow.clockwise.circle",
        "rectangle.stack.badge.plus"
    ]
    
    public init(
        serverURL: String = "http://localhost:8080",
        apiToken: String? = nil,
        syncFolder: String? = nil,
        defaultUploadFolder: String? = nil,
        newNoteAction: NewNoteAction? = nil,
        autoSync: Bool = true,
        syncInterval: Int = 30,
        deviceId: String? = nil,
        iconName: String = "tray.circle.fill"
    ) {
        self.serverURL = serverURL
        self.apiToken = apiToken
        self.syncFolder = syncFolder
        self.defaultUploadFolder = defaultUploadFolder
        self.newNoteAction = newNoteAction
        self.autoSync = autoSync
        self.syncInterval = syncInterval
        self.deviceId = deviceId ?? SyncConfig.generateDeviceId()
        self.iconName = iconName
    }
    
    private static func generateDeviceId() -> String {
        if let existing = UserDefaults.standard.string(forKey: "cairnquire_device_id") {
            return existing
        }
        let id = "mac-\(UUID().uuidString.replacingOccurrences(of: "-", with: "").prefix(12))"
        UserDefaults.standard.set(id, forKey: "cairnquire_device_id")
        return id
    }
    
    public var serverBaseURL: URL? {
        URL(string: serverURL)
    }

    public var effectiveNewNoteAction: NewNoteAction {
        newNoteAction ?? .clipboard
    }
}

public actor ConfigStore {
    public static let shared = ConfigStore()
    
    private let defaults = UserDefaults.standard
    private let keychainService = "com.cairnquire.sync"
    private let configKey = "cairnquire_config"
    
    public init() {}
    
    nonisolated public func load() -> SyncConfig {
        let defaults = UserDefaults.standard
        if let data = defaults.data(forKey: configKey),
           let config = try? JSONDecoder().decode(SyncConfig.self, from: data) {
            var config = config
            // Load token from keychain
            if let token = loadTokenFromKeychain() {
                config.apiToken = token
            }
            return config
        }
        return SyncConfig()
    }
    
    public func save(_ config: SyncConfig) {
        let defaults = UserDefaults.standard
        var configToSave = config
        let token = config.apiToken
        configToSave.apiToken = nil
        
        if let data = try? JSONEncoder().encode(configToSave) {
            defaults.set(data, forKey: configKey)
        }
        
        if let token = token {
            saveTokenToKeychain(token)
        } else {
            deleteTokenFromKeychain()
        }
    }
    
    private nonisolated func saveTokenToKeychain(_ token: String) {
        let data = token.data(using: .utf8)!
        
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: keychainService,
            kSecAttrAccount as String: "api_token"
        ]

        let attributes: [String: Any] = [
            kSecValueData as String: data,
            kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
        ]

        if SecItemUpdate(query as CFDictionary, attributes as CFDictionary) == errSecItemNotFound {
            var newItem = query
            newItem.merge(attributes) { _, new in new }
            SecItemAdd(newItem as CFDictionary, nil)
        }
    }
    
    private nonisolated func loadTokenFromKeychain() -> String? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: keychainService,
            kSecAttrAccount as String: "api_token",
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne
        ]
        
        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        
        guard status == errSecSuccess,
              let data = result as? Data,
              let token = String(data: data, encoding: .utf8) else {
            return nil
        }
        
        return token
    }
    
    private nonisolated func deleteTokenFromKeychain() {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: keychainService,
            kSecAttrAccount as String: "api_token"
        ]
        SecItemDelete(query as CFDictionary)
    }
}
