//
//  Device.swift
//  EasyFolder
//
//  Created by feng on 2019/4/22.
//  Copyright © 2019 feng. All rights reserved.
//

import Cocoa

/// 模拟器路径
///Users/{用户名}/Library/Developer/CoreSimulator/Devices

fileprivate let deviceRelativePath: String = "/Library/Developer/CoreSimulator/Devices";
fileprivate let dataReleatedContainer: String = "/data/Containers";
fileprivate let bundleReleatedContainer: String =  dataReleatedContainer + "/Bundle/Application";
fileprivate let sandboxReleateContainer: String = dataReleatedContainer + "/Data/Application";
fileprivate let groupReleatedContainer: String = dataReleatedContainer + "/Shared/AppGroup";

final class Device {
    /// 设备当前状态
    enum State: String {
        /// 未知
        case unknown;
        /// 关闭
        case shutdown;
        /// 启动
        case booting;
        /// 启动中
        case booted;
        
        init(_ rawValue: Int) {
            switch rawValue {
            case 1 : self = .shutdown;
            case 2 : self = .booting;
            case 3 : self = .booted;
            default: self = .unknown;
            }
        }
    }
    
    /// 设备类型
    enum Style: String {
        /// 未知类型
        case unknown;
        /// iPhone
        case iPhone;
        /// iPad
        case iPad;
        /// iPod
        case iPod;
        /// Apple Watch
        case watch;
        /// Apple tv
        case tv;
        
        init(_ value: String) {
            if     (value.contains("iPhone"))       { self = .iPhone; }
            else if(value.contains("iPad"))         { self = .iPad; }
            else if(value.contains("iPod"))         { self = .iPod; }
            else if(value.contains("Apple-Watch"))  { self = .watch; }
            else if(value.contains("Apple-TV"))     { self = .tv; }
            else                                    { self = .unknown; }
        }
    }
    
    /// 设备状态
    var state: State = .unknown;
    /// 设备类型
    var style: Style = .iPhone;
    
    /// 设备是否可用
    var isAvailable: Bool = false;
    /// 设备名
    var name: String = "";
    /// 设备唯一标识符
    var udid: String = "";
    
    var icon: NSImage? = nil;
    /// 设备文件路径
    var path: File!;
    
    var apps: [Application] = [];
    
    var runtime: Runtime!;
    
    fileprivate var runtimeIdenfier: String = "";
    fileprivate var typeIdentifier: String = "";
    
    enum PathKey: String {
        case bundle;
        case sandbox;
        case group
    }
    
    fileprivate(set) static var allAppsPathInfo:[String: [PathKey: [File]]] = [:];
    
    init?(_ path: String = "") {
        if path.isEmpty { return nil; }
        let plistFile = path + "/" + "device.plist"
        guard let info = NSDictionary(contentsOfFile: plistFile) as? [String: Any]
            else { return nil; }
        guard let runtime = Runtime(any2String(info["runtime"]))
            else { return nil; }
        self.runtime = runtime;
        
        self.runtimeIdenfier = runtime.identifier;
        self.path = File(path)!;
        self.udid = any2String(info["UDID"]);
        self.isAvailable = (info["isEphemeral"] != nil && (info["isEphemeral"] as! Bool) == false);
        self.typeIdentifier = any2String(info["deviceType"]);
        self.name = any2String(info["name"]);
        self.state = State(info["state"] as? Int ?? 0);
        self.style = Style.init(self.typeIdentifier);
        
        metaAppPathInfo();
        reloadApps();
        setupIcon();
    }
    
    fileprivate func setupIcon() {
        let iconName = "\(style.rawValue)-\(state.rawValue)_29x29_";
        icon = NSImage(named: iconName);
    }
    
//    deinit { log(); }
}

extension Device {
    
    fileprivate static func resetAllAppsPathInfo() {
        allAppsPathInfo.removeAll();
    }
    
    fileprivate static func deviceContainer() -> String {
        let homeDirector: String = String(cString: getpwuid(getuid())!.pointee.pw_dir);
        return homeDirector + deviceRelativePath;
    }
    
    static func allDevice(_ useCache: Bool = false) -> [Device] {
        if(!useCache) { resetAllAppsPathInfo(); }
        let devices: [Device] = File(self.deviceContainer())!
            .loadChildren(maxDepth: 1)
            .filter{ $0.isDirectory; }
            .map{Device($0.path); }
            .compactMap{ $0; }
            .filter{ $0.isAvailable; }
            .sorted{ $0.name < $1.name; }
        return devices;
    }
}

// MARK: - application action
extension Device {
    fileprivate func metaAppPathInfo() {
        
        if(Device.allAppsPathInfo[udid] != nil) { return; }
        
        Device.allAppsPathInfo[udid] = [
            PathKey.bundle: childrenContainer(at: bundleReleatedContainer),
            PathKey.sandbox: childrenContainer(at: sandboxReleateContainer),
            PathKey.group: childrenContainer(at: groupReleatedContainer)]
    }
    
    fileprivate func childrenContainer(at releatePath: String) -> [File] {
        guard let file = File(path.path + releatePath) else { return []; }
        let children = file.loadChildren(maxDepth: 1).filter{ $0.isDirectory; };
        return children;
    }
    
    /// 重新加载所有 app
    func reloadApps() {
        if let allPathAtDevice: [PathKey: [File]] = Device.allAppsPathInfo[udid] {
            let appsBundlePath: [File] = allPathAtDevice[PathKey.bundle] ?? [];
            let appsSandboxPath: [File] = allPathAtDevice[PathKey.sandbox] ?? [];
            let appsGroupPath: [File] = allPathAtDevice[PathKey.group] ?? [];
            apps = (appsBundlePath.map{ file in
                let app = Application(file, nil, [], self);
                app?.sandboxContainer = appsSandboxPath.filter{ sanboxFile in
                    guard let sandboxIndenfider = sanboxFile.metaData?.identifier,
                        let appIdentifier = file.metaData?.identifier
                        else{ return false; }
                    return sandboxIndenfider == appIdentifier;
                    }.first;
                
                app?.groups = (appsGroupPath.filter{ groupFile in
                    guard let groupIdentifier = groupFile.metaData?.identifier,
                        let appIdentifier = file.metaData?.identifier
                        else{ return false; }
                    return groupIdentifier.contains(appIdentifier);
                    }.map{ return Application.Group($0); });
                return app;
                }
                .compactMap{ $0; }
                .sorted{ $0.bundlePath.updateAt.timeIntervalSince1970 > $1.bundlePath.updateAt.timeIntervalSince1970 });
            
        }
    }
    
    /// 启动某个 app
    func launch(app: Application) {
        app.launch();
    }
    
    /// 关闭某个 app
    func halt(app: Application) {
        app.halt();
    }
    
    /// 安装某个 app
    func install(app: Application) {
        
    }
    
    /// 卸载某个 app
    func uninstall(app: Application) {
        app.uninstall();
    }
    
    /// 重置某个 app
    func reset(app: Application) {
        app.reset();
    }
}

// MARK: - device action
extension Device {
    /// 查看文件路径
    func revealInFileViewer()  {
        path.revealInFileViewer();
    }
    
    /// 拷贝到剪切板
    func copyBundlePathToPasteBoard() {
        let title = "\(name): path copied to pasteboard"
        let detail = path.path;
        let value = detail;
        showLocalNotify(title, detail, value);
    }
    
    /// 启动设备
    func boot(_ callback: (() -> ())? = nil) {
        if(state == .booted) { callback?(); return; }
        excute("xcrun instruments -w \(udid)") {
            if let message = $0 {log(message);}
        }
    }
    
    /// 关闭设备
    func halt() {
        excute("xcrun simctl shutdown \(udid)") {
            if let message = $0 {log(message);}
        }
    }
    
    /// 重置设备
    func reset() {
        excute("xcrun simctl erase \(udid)") {
            if let message = $0 {log(message);}
        }
    }
    
    /// 添加图片
    func add(photo: File)  {
        
    }
    
    /// 添加视频
    func add(video: File) {
        
    }
    
    /// 添加文件
    fileprivate func add(file: File) {
        
    }
}
