//
// Copyright 2025 Element Creations Ltd.
// Copyright 2022-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//

import Compound
import SwiftUI

struct InviteUsersScreen: View {
    @ObservedObject var context: InviteUsersScreenViewModel.Context
    
    @State private var formWidth = CGFloat.zero
    
    var showTopSection: Bool {
        !context.viewState.selectedUsers.isEmpty || context.viewState.isSearching
    }
    
    var body: some View {
        mainContent
            .compoundList()
            .scrollDismissesKeyboard(.immediately)
            .navigationTitle(L10n.screenCreateRoomAddPeopleTitle)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar { toolbar }
            .searchController(query: $context.searchQuery,
                              placeholder: L10n.commonSearchForSomeone,
                              showsCancelButton: false,
                              disablesInteractiveDismiss: true,
                              accessibilityFocusOnStart: true)
            .compoundSearchField()
            .alert(item: $context.alertInfo)
            .navigationBarBackButtonHidden(context.viewState.isSkippable)
    }
    
    // MARK: - Private
    
    private var mainContent: some View {
        Form {
            if showTopSection {
                // this is a fix for having the carousel not clipped, and inside the form, so when the search is dismissed, it wont break the design
                Section {
                    EmptyView()
                } header: {
                    VStack(spacing: 16) {
                        selectedUsersSection
                            .textCase(.none)
                            .frame(width: formWidth)
                        
                        if context.viewState.isSearching {
                            ProgressView()
                                .frame(maxWidth: .infinity, alignment: .center)
                                .listRowBackground(Color.clear)
                        }
                    }
                }
            }
            
            if context.viewState.hasEmptySearchResults {
                noResultsContent
            } else {
                usersSection
            }
        }
        .readWidth($formWidth)
    }
    
    private var noResultsContent: some View {
        Text(L10n.commonNoResults)
            .font(.compound.bodyLG)
            .foregroundColor(.compound.textSecondary)
            .frame(maxWidth: .infinity)
            .listRowBackground(Color.clear)
            .accessibilityIdentifier(A11yIdentifiers.startChatScreen.searchNoResults)
    }
    
    @ViewBuilder
    private var usersSection: some View {
        if !context.viewState.usersSection.users.isEmpty {
            Section {
                ForEach(context.viewState.usersSection.users, id: \.userID) { user in
                    UserProfileListRow(user: user,
                                       membership: context.viewState.membershipState(user),
                                       mediaProvider: context.mediaProvider,
                                       kind: .multiSelection(isSelected: context.viewState.isUserSelected(user)) {
                                           context.send(viewAction: .toggleUser(user))
                                       })
                                       .disabled(context.viewState.isUserDisabled(user))
                                       .accessibilityIdentifier(A11yIdentifiers.inviteUsersScreen.userProfile)
                }
            } header: {
                if let title = context.viewState.usersSection.title {
                    Text(title)
                        .compoundListSectionHeader()
                }
            }
        } else {
            Section.empty
        }
    }
    
    @ScaledMetric private var selectedUserCellWidth: CGFloat = 80

    private var selectedUsersSection: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 8) {
                ForEach(context.viewState.selectedUsers, id: \.userID) { user in
                    InviteUsersScreenSelectedItem(user: user, mediaProvider: context.mediaProvider) {
                        deselect(user)
                    }
                    .frame(width: selectedUserCellWidth)
                }
            }
            .padding(.horizontal, 16)
            .scrollTargetLayout()
        }
        .scrollPosition(id: $context.selectedUsersPosition, anchor: .trailing)
    }
    
    @ToolbarContentBuilder
    private var toolbar: some ToolbarContent {
        if !context.viewState.isSkippable {
            ToolbarItem(placement: .cancellationAction) {
                Button(L10n.actionCancel) {
                    context.send(viewAction: .cancel)
                }
            }
        }
        
        ToolbarItem(placement: .confirmationAction) {
            Button(context.viewState.actionText) {
                context.send(viewAction: .proceed)
            }
            .accessibilityIdentifier(A11yIdentifiers.inviteUsersScreen.proceed)
            .disabled(context.viewState.isActionDisabled)
        }
    }
    
    private func deselect(_ user: UserProfileProxy) {
        context.send(viewAction: .toggleUser(user))
    }
}

// MARK: - Previews

struct InviteUsersScreen_Previews: PreviewProvider, TestablePreview {
    static let viewModel = makeViewModel()
    static let searchingViewModel = makeViewModel(searchQuery: "Alice")
    static let selectedViewModel = makeViewModel(hasSelection: true)
    
    static var previews: some View {
        ElementNavigationStack {
            InviteUsersScreen(context: viewModel.context)
        }
        .previewDisplayName("Suggestions")
        .snapshotPreferences(expect: viewModel.context.$viewState.map { !$0.usersSection.users.isEmpty })
        
        ElementNavigationStack {
            InviteUsersScreen(context: searchingViewModel.context)
        }
        .previewDisplayName("Searching")
        .snapshotPreferences(expect: searchingViewModel.context.$viewState.map {
            $0.usersSection.type == .searchResult && !$0.usersSection.users.isEmpty
        })
        
        ElementNavigationStack {
            InviteUsersScreen(context: selectedViewModel.context)
        }
        .previewDisplayName("Selected")
        .snapshotPreferences(expect: selectedViewModel.context.$viewState.map { !$0.selectedUsers.isEmpty })
    }
    
    static func makeViewModel(searchQuery: String? = nil, hasSelection: Bool = false) -> InviteUsersScreenViewModel {
        let clientProxy = ClientProxyMock(.init())
        clientProxy.recentConversationCounterpartsReturnValue = [.mockAlice, .mockBob, .mockCharlie, .mockDan, .mockVerbose]
        
        let userDiscoveryService = UserDiscoveryServiceMock()
        userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
        
        let viewModel = InviteUsersScreenViewModel(userSession: UserSessionMock(.init(clientProxy: clientProxy)),
                                                   roomProxy: JoinedRoomProxyMock(.init(members: [])),
                                                   isSkippable: true,
                                                   userDiscoveryService: userDiscoveryService,
                                                   userIndicatorController: UserIndicatorControllerMock(),
                                                   appSettings: ServiceLocator.shared.settings)
        
        if let searchQuery {
            viewModel.context.searchQuery = searchQuery
        }
        
        if hasSelection {
            viewModel.state.selectedUsers = [.mockAlice]
        }
        
        return viewModel
    }
}
