import SwiftUI

public struct SplitView: View {
    @State private var viewModel = SybilViewModel()
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    @Environment(\.scenePhase) private var scenePhase
    @State private var shouldRefreshOnForeground = false
    @State private var composerFocusRequest = 0
    @State private var columnVisibility: NavigationSplitViewVisibility = .automatic

    private var keyboardActions: SybilKeyboardActions? {
        guard !viewModel.isCheckingSession, viewModel.isAuthenticated else {
            return nil
        }

        return SybilKeyboardActions(
            newChat: {
                viewModel.startNewChat()
                composerFocusRequest += 1
            },
            newSearch: {
                viewModel.startNewSearch()
                composerFocusRequest += 1
            },
            previousConversation: {
                viewModel.selectPreviousSidebarItem()
            },
            nextConversation: {
                viewModel.selectNextSidebarItem()
            }
        )
    }

    @MainActor public init() {
        SybilFontRegistry.registerIfNeeded()
        SybilTheme.applySystemAppearance()
    }

    public var body: some View {
        ZStack {
            SybilTheme.backgroundGradient
                .ignoresSafeArea()

            if viewModel.isCheckingSession {
                ProgressView("Checking session…")
                    .tint(SybilTheme.primary)
                    .foregroundStyle(SybilTheme.textMuted)
            } else if !viewModel.isAuthenticated {
                SybilConnectionView(viewModel: viewModel)
                    .padding()
            } else if horizontalSizeClass == .compact {
                SybilPhoneShellView(viewModel: viewModel)
            } else {
                GeometryReader { proxy in
                    NavigationSplitView(columnVisibility: $columnVisibility) {
                        SybilSidebarView(viewModel: viewModel)
                    } detail: {
                        SybilWorkspaceView(
                            viewModel: viewModel,
                            composerFocusRequest: composerFocusRequest,
                            navigationLeadingControl: splitNavigationLeadingControl(for: proxy.size),
                            onShowSidebar: showSidebar,
                            onRequestNewChat: {
                                viewModel.startNewChat()
                                composerFocusRequest += 1
                            }
                        )
                    }
                    .navigationSplitViewStyle(.balanced)
                    .tint(SybilTheme.primary)
                }
            }
        }
        .font(.sybil(.body))
        .preferredColorScheme(.dark)
        .focusedSceneValue(\.sybilKeyboardActions, keyboardActions)
        .task {
            await viewModel.bootstrap()
        }
        .onChange(of: scenePhase) { _, nextPhase in
            switch nextPhase {
            case .background:
                shouldRefreshOnForeground = true
                viewModel.markAppInactiveForNetwork()
            case .active:
                viewModel.markAppActiveForNetwork()
                guard shouldRefreshOnForeground, horizontalSizeClass != .compact else {
                    return
                }
                shouldRefreshOnForeground = false
                Task {
                    await viewModel.refreshAfterAppBecameActive(
                        refreshCollections: true,
                        refreshSelection: viewModel.hasRefreshableSelection
                    )
                }
            case .inactive:
                shouldRefreshOnForeground = true
                viewModel.markAppInactiveForNetwork()
            @unknown default:
                break
            }
        }
    }

    private func splitNavigationLeadingControl(for size: CGSize) -> SybilWorkspaceNavigationLeadingControl {
        return size.width < size.height ? .showSidebar : .hidden
    }

    private func showSidebar() {
        withAnimation(.easeInOut(duration: 0.22)) {
            columnVisibility = .all
        }
    }
}

public struct SybilCommands: Commands {
    @FocusedValue(\.sybilKeyboardActions) private var keyboardActions

    public init() {}

    public var body: some Commands {
        CommandGroup(replacing: .newItem) {
            Button("New Chat") {
                keyboardActions?.newChat()
            }
            .keyboardShortcut("n", modifiers: .command)
            .disabled(keyboardActions == nil)

            Button("New Search") {
                keyboardActions?.newSearch()
            }
            .keyboardShortcut("n", modifiers: [.command, .shift])
            .disabled(keyboardActions == nil)
        }

        CommandMenu("Conversation") {
            Button("Previous Conversation") {
                keyboardActions?.previousConversation()
            }
            .keyboardShortcut("[", modifiers: .command)
            .disabled(keyboardActions == nil)

            Button("Next Conversation") {
                keyboardActions?.nextConversation()
            }
            .keyboardShortcut("]", modifiers: .command)
            .disabled(keyboardActions == nil)
        }
    }
}

private struct SybilKeyboardActions {
    var newChat: () -> Void
    var newSearch: () -> Void
    var previousConversation: () -> Void
    var nextConversation: () -> Void
}

private struct SybilKeyboardActionsKey: FocusedValueKey {
    typealias Value = SybilKeyboardActions
}

private extension FocusedValues {
    var sybilKeyboardActions: SybilKeyboardActions? {
        get { self[SybilKeyboardActionsKey.self] }
        set { self[SybilKeyboardActionsKey.self] = newValue }
    }
}
