import AppKit
import AlignerCore

@MainActor
final class PermissionsWindowController: NSWindowController {
    private let permissionManager: any SystemPermissionManaging
    private let accessibilityStatus = NSTextField(labelWithString: "")
    private let screenRecordingStatus = NSTextField(labelWithString: "")
    var onPermissionStatusChanged: ((PermissionKind, PermissionStatus) -> Void)?
    var onPermissionRequestStarted: ((PermissionKind) -> Void)?
    private var lastKnownStatuses: [PermissionKind: PermissionStatus] = [:]
    private var refreshTimer: Timer?

    init(permissionManager: any SystemPermissionManaging) {
        self.permissionManager = permissionManager

        let window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 520, height: 280),
            styleMask: [.titled, .closable, .miniaturizable],
            backing: .buffered,
            defer: false
        )
        window.title = "Aligner Needs Permissions"
        window.center()

        super.init(window: window)
        window.contentView = makeContentView()
        refreshStatuses()
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        nil
    }

    override func showWindow(_ sender: Any?) {
        super.showWindow(sender)
        refreshStatuses()
        startRefreshing()
    }

    override func close() {
        stopRefreshing()
        super.close()
    }

    private func makeContentView() -> NSView {
        let title = NSTextField(labelWithString: "Aligner needs some permissions")
        title.font = .systemFont(ofSize: 22, weight: .semibold)

        let subtitle = NSTextField(wrappingLabelWithString: "These permissions are normal for a macOS window management app. They let Aligner focus windows and show real window previews.")
        subtitle.textColor = .secondaryLabelColor

        let stack = NSStackView()
        stack.orientation = .vertical
        stack.alignment = .leading
        stack.spacing = 18
        stack.translatesAutoresizingMaskIntoConstraints = false

        stack.addArrangedSubview(title)
        stack.addArrangedSubview(subtitle)
        stack.addArrangedSubview(permissionRow(
            title: "Accessibility",
            description: "Needed to focus or switch to the target window after you release the shortcut. If this stays red after you enable it, quit and reopen Aligner.",
            statusLabel: accessibilityStatus,
            action: #selector(requestAccessibilityPermission)
        ))
        stack.addArrangedSubview(permissionRow(
            title: "Screen Recording",
            description: "Needed to show real screenshots and previews of open windows. If this stays red after you enable it, quit and reopen Aligner.",
            statusLabel: screenRecordingStatus,
            action: #selector(requestScreenRecordingPermission)
        ))

        let root = NSView()
        root.addSubview(stack)
        NSLayoutConstraint.activate([
            stack.leadingAnchor.constraint(equalTo: root.leadingAnchor, constant: 28),
            stack.trailingAnchor.constraint(equalTo: root.trailingAnchor, constant: -28),
            stack.topAnchor.constraint(equalTo: root.topAnchor, constant: 28),
            stack.bottomAnchor.constraint(lessThanOrEqualTo: root.bottomAnchor, constant: -28)
        ])
        return root
    }

    private func permissionRow(
        title: String,
        description: String,
        statusLabel: NSTextField,
        action: Selector
    ) -> NSView {
        let titleLabel = NSTextField(labelWithString: title)
        titleLabel.font = .systemFont(ofSize: 15, weight: .semibold)

        let descriptionLabel = NSTextField(wrappingLabelWithString: description)
        descriptionLabel.textColor = .secondaryLabelColor

        let button = NSButton(title: "Request Permission...", target: self, action: action)
        button.bezelStyle = .rounded

        let row = NSStackView(views: [titleLabel, descriptionLabel, statusLabel, button])
        row.orientation = .vertical
        row.alignment = .leading
        row.spacing = 6
        return row
    }

    private func startRefreshing() {
        stopRefreshing()
        refreshTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            Task { @MainActor in
                self?.refreshStatuses()
            }
        }
    }

    private func stopRefreshing() {
        refreshTimer?.invalidate()
        refreshTimer = nil
    }

    private func refreshStatuses() {
        refresh(.accessibility, label: accessibilityStatus)
        refresh(.screenRecording, label: screenRecordingStatus)
    }

    private func refresh(_ kind: PermissionKind, label: NSTextField) {
        let status = permissionManager.status(for: kind)
        update(label, with: status)

        guard lastKnownStatuses[kind] != status else { return }
        lastKnownStatuses[kind] = status
        onPermissionStatusChanged?(kind, status)
    }

    private func update(_ label: NSTextField, with status: PermissionStatus) {
        switch status {
        case .granted:
            label.stringValue = "Granted"
            label.textColor = .systemGreen
        case .notGranted:
            label.stringValue = "Not granted"
            label.textColor = .systemRed
        }
    }

    @objc private func requestAccessibilityPermission() {
        requestPermission(
            .accessibility,
            settingsURL: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
        )
    }

    @objc private func requestScreenRecordingPermission() {
        requestPermission(
            .screenRecording,
            settingsURL: "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"
        )
    }

    private func requestPermission(_ kind: PermissionKind, settingsURL: String) {
        onPermissionRequestStarted?(kind)
        _ = permissionManager.request(kind)
        refreshStatuses()

        guard permissionManager.status(for: kind) != .granted else { return }

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
            self?.openSettings(settingsURL)
            self?.refreshStatuses()
        }
    }

    private func openSettings(_ urlString: String) {
        guard let url = URL(string: urlString) else { return }
        NSWorkspace.shared.open(url)
    }
}
