//
//  LogsHandlerLive.swift
//  secant-testnet
//
//  Created by Lukáš Korba on 30.01.2023.
//

import Foundation
import ComposableArchitecture
import OSLog

import Utils

extension LogsHandlerClient: DependencyKey {
    public static let liveValue = LogsHandlerClient(
        exportAndStoreLogs: { sdkLogs, tcaLogs, walletLogs in
            // create a directory
            let logsURL = FileManager.default.temporaryDirectory.appendingPathComponent("zashiPrivateData")
            try FileManager.default.createDirectory(atPath: logsURL.path, withIntermediateDirectories: true)
            
            // export the logs
            async let sdkLogsVerbose = LogsHandlerClient.exportAndStoreLogsFor(
                key: sdkLogs,
                atURL: logsURL.appendingPathComponent("sdkLogs_verbose.txt")
            )
            async let sdkLogsSync = LogsHandlerClient.exportAndStoreLogsFor(
                key: sdkLogs,
                atURL: logsURL.appendingPathComponent("sdkLogs_sync.txt"),
                level: .info // The info level represents the sync log in the SDK
            )
            async let tcaLogs = LogsHandlerClient.exportAndStoreLogsFor(
                key: tcaLogs,
                atURL: logsURL.appendingPathComponent("tcaLogs.txt")
            )
            async let walletLogs = LogsHandlerClient.exportAndStoreLogsFor(
                key: walletLogs,
                atURL: logsURL.appendingPathComponent("walletLogs.txt")
            )

            let logs = try await [sdkLogsVerbose, sdkLogsSync, tcaLogs, walletLogs]
            
            // store the log files into the logs folder
            try logs.forEach { logsHandler in
                try logsHandler.result.write(to: logsHandler.dir, atomically: true, encoding: String.Encoding.utf8)
            }
            
            // zip the logs folder
            let coordinator = NSFileCoordinator()
            var zipError: NSError?
            var archiveURL: URL?
            
            archiveURL = await withCheckedContinuation { continuation in
                coordinator.coordinate(readingItemAt: logsURL, options: [.forUploading], error: &zipError) { zipURL in
                    do {
                        let tmpURL = try FileManager.default.url(
                            for: .itemReplacementDirectory,
                            in: .userDomainMask,
                            appropriateFor: zipURL,
                            create: true
                        )
                        .appendingPathComponent("zashiPrivateData.zip")
                        try FileManager.default.moveItem(at: zipURL, to: tmpURL)
                        continuation.resume(returning: tmpURL)
                    } catch {
                        continuation.resume(returning: nil)
                    }
                }
            }
            
            return archiveURL
        }
    )
}

private extension LogsHandlerClient {
    static func exportAndStoreLogsFor(
        key: String,
        atURL: URL,
        level: OSLogEntryLog.Level = .debug
    ) async throws -> (result: String, dir: URL) {
        let logsStr = try await LogStore.exportCategory(
            key,
            level: level,
            fileSize: 2_000_000 // ~ 2MB of data
        )
        
        var result = ""
        logsStr?.forEach({ line in
            result.append(line)
            result.append("\n\n")
        })
        
        return (result: result, dir: atURL)
    }
}
