import Cocoa
import Carbon

/// 通过剪贴板备份 → 写入 → Cmd+V 粘贴 → 恢复剪贴板的方式注入文本
struct TextInjector {

    /// 剪贴板备份结构
    private struct PasteboardBackup {
        let items: [[String: Data]]
    }

    /// 将文本注入当前焦点输入框（异步完成剪贴板恢复）
    @discardableResult
    static func inject(_ text: String) -> Bool {
        guard !text.isEmpty else { return false }

        // 备份
        let backup = backupPasteboard()

        // 检测输入法
        let isCJK = InputSourceManager.isCJKInputSource()
        let originalSource: TISInputSource? = isCJK ? InputSourceManager.switchToASCII() : nil

        if isCJK {
            Thread.sleep(forTimeInterval: 0.05)
        }

        // 写入目标文本
        NSPasteboard.general.clearContents()
        NSPasteboard.general.setString(text, forType: .string)

        // 模拟 Cmd+V（必须在主线程 run loop 中处理）
        simulatePaste()

        // 恢复输入法（不阻塞主线程）
        if isCJK {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                InputSourceManager.restore(originalSource)
            }
        }

        // 延迟恢复剪贴板，确保粘贴事件已被目标应用处理
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            restorePasteboard(backup)
        }

        print("[Injector] Injected \"\(text.prefix(50))...\" (\(text.count) chars)")
        return true
    }

    // MARK: - 剪贴板备份/恢复

    private static func backupPasteboard() -> PasteboardBackup {
        let pb = NSPasteboard.general
        guard let items = pb.pasteboardItems, !items.isEmpty else {
            var fallback: [[String: Data]] = []
            if let str = pb.string(forType: .string),
               let data = str.data(using: .utf8) {
                fallback = [["public.utf8-plain-text": data]]
            }
            return PasteboardBackup(items: fallback)
        }

        let backedItems: [[String: Data]] = items.compactMap { item in
            var typeData: [String: Data] = [:]
            for type in item.types {
                if let data = item.data(forType: type) {
                    typeData[type.rawValue] = data
                }
            }
            return typeData.isEmpty ? nil : typeData
        }

        return PasteboardBackup(items: backedItems)
    }

    private static func restorePasteboard(_ backup: PasteboardBackup) {
        let pb = NSPasteboard.general
        pb.clearContents()

        for typeData in backup.items {
            let newItem = NSPasteboardItem()
            for (type, data) in typeData {
                newItem.setData(data, forType: NSPasteboard.PasteboardType(type))
            }
            pb.writeObjects([newItem])
        }
    }

    // MARK: - 模拟粘贴

    private static func simulatePaste() {
        let source = CGEventSource(stateID: .combinedSessionState)

        let keyDown = CGEvent(keyboardEventSource: source, virtualKey: 0x09, keyDown: true)
        keyDown?.flags = .maskCommand
        keyDown?.post(tap: .cghidEventTap)

        usleep(10_000)

        let keyUp = CGEvent(keyboardEventSource: source, virtualKey: 0x09, keyDown: false)
        keyUp?.flags = .maskCommand
        keyUp?.post(tap: .cghidEventTap)
    }
}
