import AppKit
import Foundation
import Security

private enum Action {
    case store
    case status
    case deleteTestItem
}

private struct Options {
    let service: String
    let account: String
    let label: String
    let action: Action
    let resultFile: String?
}

private enum StoreResult {
    case stored
    case cancelled
    case failed
}

private enum PresenceResult {
    case present
    case absent
    case failed
}

private func parseOptions() -> Options? {
    var service: String?
    var account: String?
    var label = "Private credential"
    var action: Action?
    var resultFile: String?
    var index = 1
    let arguments = CommandLine.arguments

    while index < arguments.count {
        let argument = arguments[index]
        switch argument {
        case "--service", "--account", "--label", "--result-file":
            guard index + 1 < arguments.count else { return nil }
            let value = arguments[index + 1]
            guard !value.isEmpty, !value.contains("\0") else { return nil }
            if argument == "--service" {
                service = value
            } else if argument == "--account" {
                account = value
            } else if argument == "--label" {
                label = value
            } else {
                resultFile = value
            }
            index += 2
        case "--store", "--status", "--delete-test-item":
            guard action == nil else { return nil }
            action = argument == "--store" ? .store
                : argument == "--status" ? .status : .deleteTestItem
            index += 1
        default:
            return nil
        }
    }

    guard let service, let account, let action, !label.isEmpty else { return nil }
    return Options(
        service: service,
        account: account,
        label: label,
        action: action,
        resultFile: resultFile
    )
}

private func deviceLocalQuery(service: String, account: String) -> [CFString: Any] {
    [
        kSecClass: kSecClassGenericPassword,
        kSecAttrService: service,
        kSecAttrAccount: account,
        kSecAttrSynchronizable: kCFBooleanFalse as Any,
    ]
}

private func storeInKeychain(
    service: String,
    account: String,
    label: String,
    secretData: Data
) -> Bool {
    let query = deviceLocalQuery(service: service, account: account)
    var item = query
    item[kSecAttrLabel] = label
    item[kSecAttrAccessible] = kSecAttrAccessibleWhenUnlockedThisDeviceOnly
    item[kSecValueData] = secretData

    let addStatus = SecItemAdd(item as CFDictionary, nil)
    if addStatus == errSecSuccess {
        return true
    }
    guard addStatus == errSecDuplicateItem else {
        return false
    }

    let updates: [CFString: Any] = [
        kSecAttrLabel: label,
        kSecAttrAccessible: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
        kSecValueData: secretData,
    ]
    return SecItemUpdate(query as CFDictionary, updates as CFDictionary) == errSecSuccess
}

private func keychainPresence(service: String, account: String) -> PresenceResult {
    var query = deviceLocalQuery(service: service, account: account)
    query[kSecMatchLimit] = kSecMatchLimitOne
    query[kSecReturnData] = kCFBooleanFalse
    let status = SecItemCopyMatching(query as CFDictionary, nil)
    if status == errSecSuccess {
        return .present
    }
    if status == errSecItemNotFound {
        return .absent
    }
    return .failed
}

private func deleteExactCanaryItem(service: String, account: String) -> Bool {
    guard service.hasPrefix("dev.codex.private-password-storage.canary."),
          account.hasPrefix("canary-") else {
        return false
    }
    let query = deviceLocalQuery(service: service, account: account)
    let status = SecItemDelete(query as CFDictionary)
    return status == errSecSuccess || status == errSecItemNotFound
}

@MainActor
private final class SecurePromptController: NSObject, NSWindowDelegate {
    private let service: String
    private let account: String
    private let itemLabel: String
    private let window: NSWindow
    private let secureField = NSSecureTextField()
    private let validationLabel = NSTextField(labelWithString: "")
    private var result: StoreResult?

    init(service: String, account: String, label: String) {
        self.service = service
        self.account = account
        self.itemLabel = label
        self.window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 440, height: 190),
            styleMask: [.titled, .closable],
            backing: .buffered,
            defer: false
        )
        super.init()
        configureWindow()
    }

    private func configureWindow() {
        window.title = "Store Private Credential"
        window.isReleasedWhenClosed = false
        window.delegate = self
        window.center()

        let content = NSView()
        window.contentView = content

        let title = NSTextField(labelWithString: itemLabel)
        title.font = NSFont.systemFont(ofSize: 15, weight: .semibold)
        title.lineBreakMode = .byTruncatingTail
        secureField.placeholderString = "Password"
        secureField.font = NSFont.systemFont(ofSize: 14)

        validationLabel.stringValue = "Password cannot be empty."
        validationLabel.textColor = .systemRed
        validationLabel.isHidden = true

        let cancelButton = NSButton(
            title: "Cancel", target: self, action: #selector(cancelPressed)
        )
        cancelButton.keyEquivalent = "\u{1b}"
        let storeButton = NSButton(
            title: "Store", target: self, action: #selector(storePressed)
        )
        storeButton.keyEquivalent = "\r"

        let pasteMenu = NSMenu()
        let pasteItem = NSMenuItem(
            title: "Paste", action: #selector(NSText.paste(_:)), keyEquivalent: ""
        )
        pasteItem.target = nil
        pasteMenu.addItem(pasteItem)
        secureField.menu = pasteMenu

        [title, secureField, validationLabel, cancelButton, storeButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            content.addSubview($0)
        }

        NSLayoutConstraint.activate([
            title.topAnchor.constraint(equalTo: content.topAnchor, constant: 24),
            title.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 24),
            title.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -24),
            secureField.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 16),
            secureField.leadingAnchor.constraint(equalTo: title.leadingAnchor),
            secureField.trailingAnchor.constraint(equalTo: title.trailingAnchor),
            secureField.heightAnchor.constraint(equalToConstant: 28),
            validationLabel.topAnchor.constraint(equalTo: secureField.bottomAnchor, constant: 6),
            validationLabel.leadingAnchor.constraint(equalTo: secureField.leadingAnchor),
            storeButton.trailingAnchor.constraint(equalTo: secureField.trailingAnchor),
            storeButton.bottomAnchor.constraint(equalTo: content.bottomAnchor, constant: -20),
            cancelButton.trailingAnchor.constraint(equalTo: storeButton.leadingAnchor, constant: -10),
            cancelButton.centerYAnchor.constraint(equalTo: storeButton.centerYAnchor),
        ])
    }

    private func installPasteMenu() {
        let mainMenu = NSMenu()
        let editMenuItem = NSMenuItem()
        let editMenu = NSMenu(title: "Edit")
        let pasteItem = NSMenuItem(
            title: "Paste", action: #selector(NSText.paste(_:)), keyEquivalent: "v"
        )
        pasteItem.keyEquivalentModifierMask = [.command]
        pasteItem.target = nil
        editMenu.addItem(pasteItem)
        editMenuItem.submenu = editMenu
        mainMenu.addItem(editMenuItem)
        NSApp.mainMenu = mainMenu
    }

    func run() -> StoreResult {
        installPasteMenu()
        NSApp.setActivationPolicy(.regular)
        NSApp.activate(ignoringOtherApps: true)
        window.makeKeyAndOrderFront(nil)
        window.makeFirstResponder(secureField)
        NSApp.run()
        return result ?? .cancelled
    }

    @objc private func storePressed() {
        guard !secureField.stringValue.isEmpty else {
            validationLabel.stringValue = "Password cannot be empty."
            validationLabel.isHidden = false
            NSSound.beep()
            window.makeFirstResponder(secureField)
            return
        }

        validationLabel.isHidden = true
        var secretData = Data(secureField.stringValue.utf8)
        let stored = storeInKeychain(
            service: service,
            account: account,
            label: itemLabel,
            secretData: secretData
        )
        secureField.stringValue = ""
        secretData.resetBytes(in: 0..<secretData.count)
        guard stored else {
            validationLabel.stringValue = "The credential could not be stored."
            validationLabel.isHidden = false
            return
        }

        result = .stored
        window.close()
    }

    @objc private func cancelPressed() {
        secureField.stringValue = ""
        result = .cancelled
        window.close()
    }

    func windowWillClose(_ notification: Notification) {
        secureField.stringValue = ""
        if result == nil {
            result = .cancelled
        }
        NSApp.stop(nil)
    }
}

@MainActor
private func runSecurePrompt(options: Options) -> StoreResult {
    let application = NSApplication.shared
    let controller = SecurePromptController(
        service: options.service,
        account: options.account,
        label: options.label
    )
    _ = application
    return controller.run()
}

private func emit(_ value: String, code: Int32, resultFile: String? = nil) -> Never {
    let data = Data((value + "\n").utf8)
    if let resultFile {
        do {
            try data.write(to: URL(fileURLWithPath: resultFile), options: .atomic)
        } catch {
            exit(74)
        }
    } else {
        FileHandle.standardOutput.write(data)
    }
    exit(code)
}

guard let options = parseOptions() else {
    emit("error", code: 64)
}

switch options.action {
case .status:
    switch keychainPresence(service: options.service, account: options.account) {
    case .present:
        emit("present", code: 0, resultFile: options.resultFile)
    case .absent:
        emit("absent", code: 1, resultFile: options.resultFile)
    case .failed:
        emit("error", code: 1, resultFile: options.resultFile)
    }
case .store:
    let storeResult = MainActor.assumeIsolated {
        runSecurePrompt(options: options)
    }
    switch storeResult {
    case .stored:
        emit("stored", code: 0, resultFile: options.resultFile)
    case .cancelled:
        emit("cancelled", code: 1, resultFile: options.resultFile)
    case .failed:
        emit("error", code: 1, resultFile: options.resultFile)
    }
case .deleteTestItem:
    guard deleteExactCanaryItem(service: options.service, account: options.account) else {
        emit("error", code: 1, resultFile: options.resultFile)
    }
    emit("absent", code: 0, resultFile: options.resultFile)
}
