//
//  MP_CacheManager.swift
//  MusicPlayer
//
//  Created by Mr.Zhou on 2024/5/23.
//

import Foundation
///缓存/归档管理工具
class MP_CacheAndArchiverManager {
    // 单例模式，提供全局访问点
    static let shared = MP_CacheAndArchiverManager()
    //文件管理器
    let fileManager = FileManager.default
    ///归档指定数据字典
//    private var archiverDic:[String: MP_PlayerRequestModel]!
    ///缓存状态更新
    private var isCompleteds:[String:Bool] = [:]
    //缓存过期时间
    private var zhoujunfeng_cacheOutTimes:TimeInterval = 172800
    private init() {
    }
    ///检查缓存文件夹总大小是否超出额度，超出进行删除调整
    func zhoujunfeng_checkAndCleanCacheFolder() {
        //存放所有的缓存文件URL
        var contents:[URL] = []
        guard let cacheDirectory = createCachePath() else {return}
        do{
            contents = try fileManager.contentsOfDirectory(at: URL(fileURLWithPath: cacheDirectory), includingPropertiesForKeys: [.creationDateKey], options: .skipsHiddenFiles)
        }catch {
            print("获取缓存文件夹内容失败：\(error.localizedDescription)")
            return
        }
        //计算缓存文件夹所有的文件总大小
        var folderSize: UInt64 = 0
        for content in contents {
            if let fileSize = try? content.resourceValues(forKeys: [.fileSizeKey]).fileSize {
                folderSize += UInt64(fileSize)
            }
        }
        //超过规定值，就清理最旧的文件
        if folderSize > 1024 * 1024 * 1024 * 2 {
            let sortedFiles = contents.sorted { (url1, url2) -> Bool in
                let creationDate1 = try? url1.resourceValues(forKeys: [.creationDateKey]).creationDate
                let creationDate2 = try? url2.resourceValues(forKeys: [.creationDateKey]).creationDate
                return creationDate1 ?? Date() < creationDate2 ?? Date()
            }
            for file in sortedFiles {
                print("清理\(file.absoluteString)的缓存文件")
                try? fileManager.removeItem(at: file)
                folderSize -= UInt64((try? file.resourceValues(forKeys: [.fileSizeKey]).fileSize) ?? 0)
                if folderSize <= 1024 * 1024 * 1024 * 2 {
                    break
                }
            }
        }
    }
    ///获取缓存文件大小值
    private func getCacheSize() -> UInt64 {
        guard let cacheDirectory = createCachePath() else {return 0}
        //存放所有的缓存文件URL
        var contents:[URL] = []
        do{
            contents = try fileManager.contentsOfDirectory(at: URL(fileURLWithPath: cacheDirectory), includingPropertiesForKeys: [.creationDateKey], options: .skipsHiddenFiles)
        }catch {
            print("获取缓存文件夹内容失败：\(error.localizedDescription)")
            return 0
        }
        //计算缓存文件夹所有的文件总大小
        var folderSize: UInt64 = 0
        for content in contents {
            if let fileSize = try? content.resourceValues(forKeys: [.fileSizeKey]).fileSize {
                folderSize += UInt64(fileSize)
            }
        }
        return folderSize
    }
    func getCacheSizeText() -> String {
        let byteCountFormatter = ByteCountFormatter()
        byteCountFormatter.allowedUnits = [.useBytes, .useKB, .useMB, .useGB]
        byteCountFormatter.countStyle = .file
        return byteCountFormatter.string(fromByteCount: Int64(getCacheSize()))
    }
    
    
    ///清理所有的音乐缓存文件
    func cleanAllCache(_ compleHandler:((Bool) -> Void)?) {
        guard let cacheDirectory = createCachePath() else {return}
        //获取这个文件夹中所有内容
        do{
            let contents = try fileManager.contentsOfDirectory(atPath: cacheDirectory)
            for item in contents {
                let itemPath = (cacheDirectory as NSString).appendingPathComponent(item)
                print("清理\(item)的缓存文件")
                try fileManager.removeItem(atPath: itemPath)
            }
            //清理完成，回调数据
            print("已清理了所有缓存数据")
            if let block = compleHandler {
                block(true)
            }
        }catch{
            print("Error clearing folder contents: \(error.localizedDescription)")
            if let block = compleHandler {
                block(false)
            }
        }
    }
    
    ///创建播放器缓存文件
    func createCachePath() -> String? {
        // 所有缓存文件都放在了沙盒Cache文件夹下MP_PlayerCache文件夹里
        let cacheDirectory = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
        let path = cacheDirectory+"/"+"MP_PlayerCache"
        //检索这个缓存文件夹是否存在
        guard fileManager.fileExists(atPath: path) == false else {
            //存在，直接返回这个文件夹
            return path
        }
        //不存在
        do {
            //创建这个缓存文件夹
            try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
            return path
        } catch {
            //创建失败
            print("创建播放器缓存文件夹失败，失败原因:\(error)")
            return nil
        }
    }
    ///创建一个临时文件
    func createTempFile(_ videoID:String) -> Bool {
        //设置临时文件
        let path = tempPath(videoID)
        if fileManager.fileExists(atPath: path) {
            //存在这个临时文件，将其删除
            do{
                try fileManager.removeItem(atPath: path)
            }catch {
                print("删除临时文件失败，error: \(error)")
            }
        }
        //生成临时文件
        return fileManager.createFile(atPath: path, contents: nil, attributes: nil)
    }
    ///往临时文件中写入缓存数据
    func writeDataToAudioFileTempPathWithData(_ data:Data, videoId:String) {
        guard  let handle = FileHandle(forWritingAtPath: tempPath(videoId)) else {return}
        if #available(iOS 13.4, *) {
            do{
                try handle.seekToEnd()
            }catch {
                print("Seek到末尾失败，失败原因:\(error)")
            }
        } else {
            handle.seekToEndOfFile()
        }
        //在最后写入数据
        if #available(iOS 13.4, *) {
            do{
                try handle.write(contentsOf: data)
            }catch{
                print("写入数据失败，失败原因:\(error)")
            }
        } else {
            handle.write(data)
        }
        do {
             if #available(iOS 13.4, *) {
                 try? handle.close()  // 尝试关闭文件句柄
             } else {
                 handle.closeFile()
             }
         }
    }
    ///读取临时文件数据
    func readTempFileDataWithOffset(_ offset:UInt64, length:Int, videoId:String) -> Data? {
        var allhandle:FileHandle!
        //检索当前数据是否下载完毕了
        if isCompleteds[videoId] == true {
            //临时文件已经销毁，当前下载内容已经移动到缓存文件中，从缓存文件中读取
            let path = audioCachedPath() ?? ""
            let audioName = "/"+videoId+".mp4"
            let cachePath = path+audioName
            guard let handle = FileHandle(forReadingAtPath: cachePath) else {return nil}
            allhandle = handle
        }else {
            let path = tempPath(videoId)
            guard  let handle = FileHandle(forReadingAtPath: path) else {return nil}
            allhandle = handle
        }
        if #available(iOS 13.0, *) {
            do{
                try allhandle.seek(toOffset: offset)
            }catch{
                print("Seek到指定位置失败，失败原因:\(error)")
                try? allhandle.close()
            }
        } else {
            allhandle.seek(toFileOffset: offset)
        }
        if #available(iOS 13.4, *) {
            do{
                let data = try allhandle.read(upToCount: length)
                try allhandle.close()
                return data
            }catch{
                print("读取到指定位置失败，失败原因:\(error)")
                return nil
            }
        } else {
            let data = allhandle.readData(ofLength: length)
            allhandle.closeFile()
            return data
        }
    }
    
    /// 保存临时文件到缓存文件夹
    /// - Parameter videoId: 使用videoId作为文件名
    func moveAudioFileFromTempPathToCachePath(_ videoId: String) -> Bool {
        guard let path = audioCachedPath() else {return false }
        // 1. 判断文件夹是否存在
        if !(fileManager.fileExists(atPath: path)) {
            //不存在
            do{
                try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true)
            }catch {
                print("创建缓存夹失败,失败原因:\(error)")
                return false
            }
        }
        let audioName = "/"+videoId+".mp4"
        let cachePath = path+audioName
        // 检查目标文件是否存在，如果存在，则删除
        if fileManager.fileExists(atPath: cachePath) {
//            do {
//                print("缓存文件已经存在")
//                try fileManager.removeItem(atPath: cachePath)
//            } catch {
//                print("删除现有文件失败，失败原因: \(error)")
//                return false
//            }
            return true
        }
        // 2. 确保源文件存在
        let tempFilePath = tempPath(videoId)
        guard fileManager.fileExists(atPath: tempFilePath) else {
//            print("源文件不存在于临时路径: \(tempFilePath)")
            return false
        }
        // 3. 尝试移动文件
        do {
            try fileManager.moveItem(atPath: tempFilePath, toPath: cachePath)
//            print("\(videoId)下载完毕，移动到:\(cachePath)")
            //当前加载器加载完成
            isCompleteds[videoId] = true
            return true
        } catch {
            print("移动 \(videoId) 缓存文件失败，失败原因: \(error)")
//            deleteKeyValueIfHaveArchivedWithVideoId(videoId) // 执行额外的清理操作
            return false
        }
    }
    ///生成缓存文件
    private func audioCachedPath() -> String? {
        return (createCachePath() ?? "")
    }
    
    ///创建一个固定的临时文件路径
    private func tempPath(_ videoID:String) -> String {
        return (NSTemporaryDirectory())+"/"+"\(videoID).mp4"
    }

    ///根据VideoID获取缓存文件
    func zhoujunfeng_getCachePath(_ videoId:String) -> String? {
        //获取缓存文件夹
        guard let path = MP_CacheAndArchiverManager.shared.createCachePath() else {
            return nil
        }
        //根据videoId获取缓存文件
        let audioName = "/"+videoId+".mp4"
        //缓存文件地址
        let audioPath = path+audioName
        //检查文件是否存在
        if fileManager.fileExists(atPath: audioPath) {
            var attributes:[FileAttributeKey : Any]
            //存在，检查是否缓存过期
            do{
                // 获取指定文件的属性
                attributes = try fileManager.attributesOfItem(atPath: audioPath)
            }catch {
                //获取文件属性失败
                print("获取\(videoId)的属性失败，失败原因:\(error.localizedDescription)")
                return nil
            }
            // 从属性字典中提取创建时间
            if let creationDate = attributes[.creationDate] as? Date {
//                print("\(videoId)的创建时间是：",creationDate)
                //检索文件是否过期
                if Date().timeIntervalSince(creationDate) < zhoujunfeng_cacheOutTimes {
                    //没过期
                    return audioPath
                }else {
                    //过期了
                    zhoujunfeng_deleteCachePath(audioPath, videoId: videoId)
                    return nil
                }
            } else {
                print("\(videoId)无法获取文件的创建时间。")
                return nil
            }
        }else {
            //不存在
            return nil
        }
    }
    //删除缓存过期文件
    func zhoujunfeng_deleteCachePath(_ path:String, videoId:String) {
        do{
            try fileManager.removeItem(atPath: path)
            print("\(videoId)的缓存文件已经删除")
        }catch{
            print("\(videoId)的缓存文件删除失败，失败原因:\(error.localizedDescription)")
        }
    }
}
