//
// 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 SwiftUI

struct DeveloperOptionsScreen: View {
    @Bindable var context: DeveloperOptionsScreenViewModel.Context
    
    @State private var showConfetti = false
    @State private var elementCallURLOverrideString: String
    
    init(context: DeveloperOptionsScreenViewModel.Context) {
        self.context = context
        elementCallURLOverrideString = context.elementCallBaseURLOverride?.absoluteString ?? ""
    }
    
    var body: some View {
        Form {
            if let storeSizes = context.viewState.storeSizes {
                Section("Usage") {
                    ForEach(storeSizes) { storeSize in
                        LabeledContent(storeSize.name, value: storeSize.size)
                    }
                }
            }
            
            Section("Logging") {
                LogLevelConfigurationView(logLevel: $context.logLevel)
                
                DisclosureGroup("SDK trace packs") {
                    ForEach(TraceLogPack.allCases, id: \.self) { pack in
                        Toggle(isOn: $context.traceLogPacks[pack]) {
                            Text(pack.title)
                        }
                    }
                }
            }
            
            Section("General") {
                Toggle(isOn: $context.linkNewDeviceEnabled) {
                    Text("Link new device with QR code")
                }
                
                context.viewState.appHooks
                    .developerOptionsScreenHook
                    .generalSectionRows()
            }
            
            Section("Room List") {
                Toggle(isOn: $context.publicSearchEnabled) {
                    Text("Public search")
                }
                
                Toggle(isOn: $context.hideUnreadMessagesBadge) {
                    Text("Hide grey dots")
                }
                
                Toggle(isOn: $context.fuzzyRoomListSearchEnabled) {
                    Text("Fuzzy searching")
                }
                
                Toggle(isOn: $context.lowPriorityFilterEnabled) {
                    Text("Low priority filter")
                }
            }
            
            Section("Timeline") {
                Toggle(isOn: $context.linkPreviewsEnabled) {
                    Text("Link previews")
                    Text("Follows the timeline media visibility settings.")
                    Text("Can leak the device IP address when loading link metadata.")
                        .foregroundStyle(.compound.textCriticalPrimary)
                }
                
                Toggle(isOn: $context.liveLocationSharingEnabled) {
                    Text("Live location sharing")
                }
                
                Toggle(isOn: $context.floatingTimelineDateEnabled) {
                    Text("Floating timeline date")
                    Text("Shows a floating date badge while scrolling the timeline.")
                }
            }
                        
            Section("Join rules") {
                Toggle(isOn: $context.knockingEnabled) {
                    Text("Knocking")
                    Text("Ask to join rooms")
                }
            }
            
            Section {
                Toggle(isOn: $context.enableOnlySignedDeviceIsolationMode) {
                    Text("Exclude insecure devices when sending/receiving messages")
                    Text("Requires app reboot")
                }
            } header: {
                Text("Trust and Decoration")
            } footer: {
                Text("This setting controls how end-to-end encryption (E2EE) keys are exchanged. Enabling it will prevent the inclusion of devices that have not been explicitly verified by their owners.")
            }

            Section {
                Toggle(isOn: $context.enableKeyShareOnInvite) {
                    Text("Share encrypted history with new members")
                    Text("Requires app reboot")
                }
            } footer: {
                Text("When inviting a user to an encrypted room that has history visibility set to \"shared\", share encrypted history with that user, and accept encrypted history when you are invited to such a room.")
                Text("WARNING: this feature is EXPERIMENTAL and not all security precautions are implemented. Do not enable on production accounts.")
            }

            Section {
                TextField("Leave empty to use EC locally", text: $elementCallURLOverrideString)
                    .autocorrectionDisabled(true)
                    .autocapitalization(.none)
                    .foregroundColor(URL(string: elementCallURLOverrideString) == nil ? .red : .primary)
                    .submitLabel(.done)
                    .onSubmit {
                        if elementCallURLOverrideString.isEmpty {
                            context.elementCallBaseURLOverride = nil
                        } else if let url = URL(string: elementCallURLOverrideString) {
                            context.elementCallBaseURLOverride = url
                        }
                    }
            } header: {
                Text("Element Call remote URL override")
            }
            
            Section("Notifications") {
                Toggle(isOn: $context.hideQuietNotificationAlerts) {
                    Text("Hide quiet alerts")
                    Text("The badge count will still be updated")
                }
                Toggle(isOn: $context.focusEventOnNotificationTap) {
                    Text("Focus event on notification tap")
                }
            }
            
            Section {
                Button {
                    showConfetti = true
                } label: {
                    Text("🥳")
                        .frame(maxWidth: .infinity)
                        .alignmentGuide(.listRowSeparatorLeading) { _ in 0 } // Fix separator alignment
                }
            }

            Section {
                Button(role: .destructive) {
                    context.send(viewAction: .clearCache)
                } label: {
                    Text("Clear cache")
                        .frame(maxWidth: .infinity)
                }
            }
        }
        .overlay(effectsView)
        .navigationTitle(L10n.commonDeveloperOptions)
        .navigationBarTitleDisplayMode(.inline)
    }

    @ViewBuilder
    private var effectsView: some View {
        if showConfetti {
            EffectsView(effect: .confetti)
                .ignoresSafeArea()
                .allowsHitTesting(false)
                .task { await removeConfettiAfterDelay() }
        }
    }

    private func removeConfettiAfterDelay() async {
        try? await Task.sleep(for: .seconds(4))
        showConfetti = false
    }
}

private struct LogLevelConfigurationView: View {
    @Binding var logLevel: LogLevel
    
    var body: some View {
        Picker(selection: $logLevel) {
            ForEach(logLevels, id: \.self) { logLevel in
                Text(logLevel.title)
            }
        } label: {
            Text("Log level")
            Text("Requires app reboot")
        }
    }
    
    /// Allows the picker to work with associated values
    private var logLevels: [LogLevel] {
        [.error, .warn, .info, .debug, .trace]
    }
}

private extension Set<TraceLogPack> {
    /// A custom subscript that allows binding a toggle to add/remove a pack from the array.
    subscript(pack: TraceLogPack) -> Bool {
        get { contains(pack) }
        set {
            if newValue {
                insert(pack)
            } else {
                remove(pack)
            }
        }
    }
}

// MARK: - Previews

struct DeveloperOptionsScreen_Previews: PreviewProvider {
    static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings,
                                                           elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL,
                                                           appHooks: AppHooks(),
                                                           clientProxy: ClientProxyMock(.init()))
    static var previews: some View {
        ElementNavigationStack {
            DeveloperOptionsScreen(context: viewModel.context)
        }
    }
}
