import Foundation

public struct QuickSwitchSelection: Equatable, Sendable {
    public let appGroupIndex: Int
    public let windowIndex: Int
    public let windowID: UInt32

    public init(appGroupIndex: Int, windowIndex: Int, windowID: UInt32) {
        self.appGroupIndex = appGroupIndex
        self.windowIndex = windowIndex
        self.windowID = windowID
    }
}

public enum QuickSwitchKeyboardDirection: Equatable, Sendable {
    case left
    case right
    case up
    case down
}

public enum QuickSwitchVisualState: Equatable, Sendable {
    case normal
    case hover
    case selected
    case selectedAndHover
}

public enum QuickSwitchFocusPolicy {
    public static func initialSelection(in snapshot: QuickSwitchSnapshot) -> QuickSwitchSelection? {
        for (appGroupIndex, group) in snapshot.appGroups.enumerated() {
            guard let firstWindow = group.windows.first else { continue }

            return QuickSwitchSelection(
                appGroupIndex: appGroupIndex,
                windowIndex: 0,
                windowID: firstWindow.window.id
            )
        }

        return nil
    }

    public static func nextSelection(
        from current: QuickSwitchSelection,
        in snapshot: QuickSwitchSnapshot,
        direction: QuickSwitchKeyboardDirection
    ) -> QuickSwitchSelection? {
        nextSelection(from: current, in: snapshot, direction: direction, columnHistory: [:])
    }

    public static func nextSelection(
        from current: QuickSwitchSelection,
        in snapshot: QuickSwitchSnapshot,
        direction: QuickSwitchKeyboardDirection,
        columnHistory: [Int: Int]
    ) -> QuickSwitchSelection? {
        guard snapshot.appGroups.indices.contains(current.appGroupIndex) else {
            return initialSelection(in: snapshot)
        }

        let currentGroup = snapshot.appGroups[current.appGroupIndex]
        guard currentGroup.windows.indices.contains(current.windowIndex) else {
            return selection(appGroupIndex: current.appGroupIndex, windowIndex: 0, in: snapshot)
        }

        switch direction {
        case .left:
            return selectionInTargetColumn(
                current: current,
                targetAppGroupIndex: max(0, current.appGroupIndex - 1),
                snapshot: snapshot,
                columnHistory: columnHistory
            )
        case .right:
            return selectionInTargetColumn(
                current: current,
                targetAppGroupIndex: min(snapshot.appGroups.count - 1, current.appGroupIndex + 1),
                snapshot: snapshot,
                columnHistory: columnHistory
            )
        case .up:
            return selection(
                appGroupIndex: current.appGroupIndex,
                windowIndex: max(0, current.windowIndex - 1),
                in: snapshot
            )
        case .down:
            return selection(
                appGroupIndex: current.appGroupIndex,
                windowIndex: min(currentGroup.windows.count - 1, current.windowIndex + 1),
                in: snapshot
            )
        }
    }

    public static func visualState(
        for index: Int,
        selectedIndex: Int?,
        hoveredIndex: Int?
    ) -> QuickSwitchVisualState {
        switch (selectedIndex == index, hoveredIndex == index) {
        case (true, true):
            return .selectedAndHover
        case (true, false):
            return .selected
        case (false, true):
            return .hover
        case (false, false):
            return .normal
        }
    }

    private static func selectionInTargetColumn(
        current: QuickSwitchSelection,
        targetAppGroupIndex: Int,
        snapshot: QuickSwitchSnapshot,
        columnHistory: [Int: Int]
    ) -> QuickSwitchSelection? {
        guard targetAppGroupIndex != current.appGroupIndex else {
            return current
        }

        let rememberedWindowIndex = columnHistory[targetAppGroupIndex] ?? 0
        return selection(
            appGroupIndex: targetAppGroupIndex,
            windowIndex: rememberedWindowIndex,
            in: snapshot
        )
    }

    private static func selection(
        appGroupIndex: Int,
        windowIndex: Int,
        in snapshot: QuickSwitchSnapshot
    ) -> QuickSwitchSelection? {
        guard snapshot.appGroups.indices.contains(appGroupIndex) else {
            return nil
        }

        let group = snapshot.appGroups[appGroupIndex]
        guard !group.windows.isEmpty else {
            return nil
        }

        let boundedWindowIndex = min(max(windowIndex, 0), group.windows.count - 1)
        return QuickSwitchSelection(
            appGroupIndex: appGroupIndex,
            windowIndex: boundedWindowIndex,
            windowID: group.windows[boundedWindowIndex].window.id
        )
    }
}
