import Foundation

struct PrototypeStoreResetResult: Equatable {
    let didReset: Bool
    let removedURLs: [URL]
}

enum PrototypeStoreResetPolicy {
    static let currentGeneration = 1
    static let defaultsKey = "hp_prototypeStoreResetGeneration"
    static let manualResetDefaultsKey = "hp_prototypeStoreResetScheduled"
    static let manualResetMarkerFileName = ".HealthProbeResetScheduled"

    static func isResetScheduled(
        defaults: UserDefaults = .standard,
        appSupportURL: URL? = nil,
        fileManager: FileManager = .default
    ) -> Bool {
        if defaults.bool(forKey: manualResetDefaultsKey) || defaults.integer(forKey: defaultsKey) < currentGeneration {
            return true
        }
        guard let appSupportURL else { return false }
        return fileManager.fileExists(atPath: manualResetMarkerURL(appSupportURL: appSupportURL).path)
    }

    static func requestResetOnNextLaunch(
        defaults: UserDefaults = .standard,
        appSupportURL: URL = .applicationSupportDirectory,
        fileManager: FileManager = .default
    ) {
        defaults.set(true, forKey: manualResetDefaultsKey)
        defaults.synchronize()
        try? fileManager.createDirectory(at: appSupportURL, withIntermediateDirectories: true)
        try? Data(Date().ISO8601Format().utf8).write(
            to: manualResetMarkerURL(appSupportURL: appSupportURL),
            options: [.atomic]
        )
    }

    static func applyIfNeeded(
        appSupportURL: URL = .applicationSupportDirectory,
        defaults: UserDefaults = .standard,
        fileManager: FileManager = .default
    ) throws -> PrototypeStoreResetResult {
        guard isResetScheduled(defaults: defaults, appSupportURL: appSupportURL, fileManager: fileManager) else {
            return PrototypeStoreResetResult(didReset: false, removedURLs: [])
        }

        var removedURLs: [URL] = []
        for url in destructiveResetURLs(appSupportURL: appSupportURL) {
            guard fileManager.fileExists(atPath: url.path) else { continue }
            try fileManager.removeItem(at: url)
            removedURLs.append(url)
        }

        defaults.set(currentGeneration, forKey: defaultsKey)
        defaults.set(false, forKey: manualResetDefaultsKey)
        defaults.synchronize()
        try? fileManager.removeItem(at: manualResetMarkerURL(appSupportURL: appSupportURL))
        return PrototypeStoreResetResult(didReset: true, removedURLs: removedURLs)
    }

    static func destructiveResetURLs(appSupportURL: URL) -> [URL] {
        sidecarURLs(
            forBaseNames: [
                "HealthProbeRecords.store",
                "HealthProbeCloud.store",
                "HealthProbeArchive.sqlite",
                "HealthProbeCache.sqlite"
            ],
            appSupportURL: appSupportURL
        )
    }

    private static func sidecarURLs(forBaseNames baseNames: [String], appSupportURL: URL) -> [URL] {
        baseNames.flatMap { baseName in
            let baseURL = appSupportURL.appending(path: baseName)
            return [
                baseURL,
                appSupportURL.appending(path: "\(baseName)-shm"),
                appSupportURL.appending(path: "\(baseName)-wal"),
                appSupportURL.appending(path: "\(baseName)-journal"),
                appSupportURL.appending(path: "\(baseName).shm"),
                appSupportURL.appending(path: "\(baseName).wal"),
                appSupportURL.appending(path: "\(baseName).journal")
            ]
        }
    }

    private static func manualResetMarkerURL(appSupportURL: URL) -> URL {
        appSupportURL.appending(path: manualResetMarkerFileName)
    }
}
