import Foundation
import Security

final class SecureStore: ObservableObject {
    static let shared = SecureStore()

    @Published private(set) var deviceUid: String?
    @Published private(set) var apiToken: String?
    @Published private(set) var signingSecret: String?
    @Published private(set) var deviceName: String?
    @Published private(set) var brandAppName: String?
    @Published private(set) var brandLogoUrl: String?
    @Published private(set) var companyName: String?
    @Published private(set) var companySlug: String?
    @Published private(set) var accessBlocked = false
    @Published private(set) var accessBlockedMessage: String?

    private let service = "com.notifyhub.app"

    var displayAppName: String {
        if let brandAppName, !brandAppName.isEmpty {
            return brandAppName
        }
        return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String
            ?? Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String
            ?? "App"
    }

    var isRegistered: Bool {
        guard let deviceUid, let apiToken else { return false }
        return !deviceUid.isEmpty && !apiToken.isEmpty
    }

    private init() {
        deviceUid = read(key: "device_uid")
        apiToken = read(key: "api_token")
        signingSecret = read(key: "signing_secret")
        deviceName = read(key: "device_name")
        brandAppName = read(key: "brand_app_name")
        brandLogoUrl = read(key: "brand_logo_url")
        companyName = read(key: "company_name")
        companySlug = read(key: "company_slug")
        accessBlocked = read(key: "access_blocked") == "1"
        accessBlockedMessage = read(key: "access_blocked_message")
    }

    func saveRegistration(
        deviceUid: String,
        apiToken: String,
        signingSecret: String?,
        deviceName: String
    ) {
        clearAccessBlock()
        self.deviceUid = deviceUid
        self.apiToken = apiToken
        self.signingSecret = signingSecret
        self.deviceName = deviceName
        write(key: "device_uid", value: deviceUid)
        write(key: "api_token", value: apiToken)
        write(key: "signing_secret", value: signingSecret)
        write(key: "device_name", value: deviceName)
    }

    func markAccessBlocked(message: String) {
        accessBlocked = true
        accessBlockedMessage = message
        write(key: "access_blocked", value: "1")
        write(key: "access_blocked_message", value: message)
    }

    func clearAccessBlock() {
        accessBlocked = false
        accessBlockedMessage = nil
        delete(key: "access_blocked")
        delete(key: "access_blocked_message")
    }

    func applyBranding(_ branding: BrandingPayload?) {
        guard let branding else { return }
        brandAppName = branding.app_name
        brandLogoUrl = branding.logo_url
        write(key: "brand_app_name", value: branding.app_name)
        write(key: "brand_logo_url", value: branding.logo_url)
    }

    func applyCompany(_ company: CompanySummary?) {
        guard let company else { return }
        companyName = company.name
        companySlug = company.slug
        write(key: "company_name", value: company.name)
        write(key: "company_slug", value: company.slug)
    }

    func clearSession() {
        deviceUid = nil
        apiToken = nil
        signingSecret = nil
        deviceName = nil
        brandAppName = nil
        brandLogoUrl = nil
        companyName = nil
        companySlug = nil
        clearAccessBlock()
        delete(key: "device_uid")
        delete(key: "api_token")
        delete(key: "signing_secret")
        delete(key: "device_name")
        delete(key: "brand_app_name")
        delete(key: "brand_logo_url")
        delete(key: "company_name")
        delete(key: "company_slug")
    }

    private func write(key: String, value: String?) {
        delete(key: key)
        guard let value, let data = value.data(using: .utf8) else { return }

        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: key,
            kSecValueData as String: data,
        ]
        SecItemAdd(query as CFDictionary, nil)
    }

    private func read(key: String) -> String? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: key,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne,
        ]

        var item: CFTypeRef?
        guard SecItemCopyMatching(query as CFDictionary, &item) == errSecSuccess,
              let data = item as? Data,
              let value = String(data: data, encoding: .utf8)
        else {
            return nil
        }

        return value
    }

    private func delete(key: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: key,
        ]
        SecItemDelete(query as CFDictionary)
    }
}
