using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.IO;
using C4IT.LIAM;
using C4IT.Logging;
using C4IT.Matrix42.ServerInfo;
using C4IT_IAM_Engine;
using LiamWorkflowActivities;
using LiamAD;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace LiamWorkflowDiagnostics
{
    public partial class MainWindow : Window
    {
        private const int MsTeamsVisibilityPrivate = 0;
        private const int MsTeamsVisibilityPublic = 1;
        private const int MsTeamsVisibilityHiddenMembership = 2;
        private const int MsTeamsCloneAppsFlag = 1;
        private const int MsTeamsCloneTabsFlag = 2;
        private const int MsTeamsCloneSettingsFlag = 4;
        private const int MsTeamsCloneChannelsFlag = 8;
        private const int MsTeamsCloneMembersFlag = 16;

        private readonly ObservableCollection<string> _logEntries = new ObservableCollection<string>();
        private ProviderTestSession _session;
        private bool _isInitializingUi;
        private readonly object _diagnosticsLogSync = new object();
        private string _diagnosticsGuiLogPath;
        private string _diagnosticsStandardLogPath;
        private readonly string _settingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LiamWorkflowDiagnostics.settings.json");

        public MainWindow()
        {
            InitializeComponent();
            LogListBox.ItemsSource = _logEntries;
            InitializeLogging();
            _isInitializingUi = true;
            try
            {
                InitializeCombos();
                MaxDepthTextBox.Text = "1";
                LoadSettings();
                UpdateProviderActionPanel();
                ToggleActionButtons(true);
            }
            finally
            {
                _isInitializingUi = false;
            }
            this.Closing += MainWindow_Closing;
            AppendLog("Diagnostics tool bereit.");
        }

        private void InitializeLogging()
        {
            try
            {
                var baseDir = AppDomain.CurrentDomain.BaseDirectory;
                var logDirectory = Path.Combine(baseDir, "logs");
                Directory.CreateDirectory(logDirectory);
                _diagnosticsStandardLogPath = Path.Combine(logDirectory, "LiamWorkflowDiagnostics.log");
                _diagnosticsGuiLogPath = Path.Combine(logDirectory, "LiamWorkflowDiagnostics.gui.log");
                cLogManagerFile.CreateInstance(_diagnosticsStandardLogPath);
                cLogManager.Instance.Level = LogLevels.Debug;
                AppendLog($"GUI-Logdatei: {_diagnosticsGuiLogPath}");
                AppendLog($"Standard-Logdatei: {_diagnosticsStandardLogPath} (Level: Debug)");
            }
            catch (Exception ex)
            {
                AppendLog($"Konnte Logging nicht initialisieren: {ex.Message}", LogLevels.Warning);
            }
        }

        private void InitializeCombos()
        {
            var providerTypes = new[]
            {
                eLiamProviderTypes.MsTeams,
                eLiamProviderTypes.Ntfs,
                eLiamProviderTypes.ActiveDirectory,
                eLiamProviderTypes.Exchange
            };
            ProviderTypeCombo.ItemsSource = providerTypes;
            ProviderTypeCombo.SelectedItem = eLiamProviderTypes.MsTeams;

            GroupStrategyCombo.ItemsSource = Enum.GetValues(typeof(eLiamGroupStrategies)).Cast<eLiamGroupStrategies>();
            GroupStrategyCombo.SelectedItem = eLiamGroupStrategies.Ntfs_AGDLP;
            AdScopeComboBox.ItemsSource = Enum.GetValues(typeof(eLiamAccessRoleScopes))
                .Cast<eLiamAccessRoleScopes>()
                .Where(i => i != eLiamAccessRoleScopes.Unknown);
            AdScopeComboBox.SelectedItem = eLiamAccessRoleScopes.Universal;
            AdGroupTypeComboBox.ItemsSource = Enum.GetValues(typeof(ADServiceGroupCreator.ADGroupType))
                .Cast<ADServiceGroupCreator.ADGroupType>();
            AdGroupTypeComboBox.SelectedItem = ADServiceGroupCreator.ADGroupType.Distribution;
            MsTeamsVisibilityComboBox.ItemsSource = new[]
            {
                new MsTeamsVisibilityOption(MsTeamsVisibilityPrivate, "Private"),
                new MsTeamsVisibilityOption(MsTeamsVisibilityPublic, "Public"),
                new MsTeamsVisibilityOption(MsTeamsVisibilityHiddenMembership, "HiddenMembership")
            };
            MsTeamsVisibilityComboBox.DisplayMemberPath = nameof(MsTeamsVisibilityOption.Label);
            MsTeamsVisibilityComboBox.SelectedValuePath = nameof(MsTeamsVisibilityOption.Value);
            MsTeamsVisibilityComboBox.SelectedValue = MsTeamsVisibilityPrivate;
            MsTeamsCloneSettingsCheckBox.IsChecked = true;
            MsTeamsCloneChannelsCheckBox.IsChecked = true;
            WhatIfCheckBox.IsChecked = true;

            FetchDataAreasButton.IsEnabled = false;
            FetchSecurityGroupsButton.IsEnabled = false;
        }

        private void AppendLog(string message, LogLevels level = LogLevels.Info)
        {
            if (message == null)
            {
                message = string.Empty;
            }
            void AddEntry()
            {
                var timestamped = $"{DateTime.Now:HH:mm:ss} {message}";
                _logEntries.Add(timestamped);
                LogListBox.ScrollIntoView(timestamped);
                StatusTextBlock.Text = message;
            }

            if (!Dispatcher.CheckAccess())
            {
                Dispatcher.Invoke(AddEntry);
            }
            else
            {
                AddEntry();
            }

            try
            {
                if (!string.IsNullOrWhiteSpace(_diagnosticsGuiLogPath))
                {
                    var fileLine = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{level}] {message}{Environment.NewLine}";
                    lock (_diagnosticsLogSync)
                    {
                        File.AppendAllText(_diagnosticsGuiLogPath, fileLine, Encoding.UTF8);
                    }
                }
            }
            catch { /* ignore */ }
        }

        private void AppendLogMultiline(string text, LogLevels level = LogLevels.Info)
        {
            if (string.IsNullOrEmpty(text))
                return;

            foreach (var line in text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None))
            {
                AppendLog(line, level);
            }
        }

        private async void InitializeButton_Click(object sender, RoutedEventArgs e)
        {
            ToggleActionButtons(false);
            try
            {
                var providerData = BuildProviderDataFromFields();
                var maskToken = string.IsNullOrWhiteSpace(MaskTokenTextBox.Text) ? "***" : MaskTokenTextBox.Text.Trim();
                var providerConfigClassId = (ProviderConfigIdTextBox.Text ?? string.Empty).Trim();
                var providerConfigObjectId = (ProviderConfigObjectIdTextBox.Text ?? string.Empty).Trim();

                ApplyMatrix42Environment(ServerNameTextBox.Text, UseHttpsCheckBox.IsChecked ?? false);
                ApplyLicense(LicenseTextBox.Text);

                var session = new ProviderTestSession(msg => AppendLog(msg));
                _session = session;
                var success = await Task.Run(() => session.InitializeAsync(providerData, maskToken, CreateProviderInstance, providerConfigClassId, providerConfigObjectId));
                if (success)
                {
                    AppendLog("Provider initialisiert und authentifiziert.", LogLevels.Info);
                    ResultTextBox.Text = session.SanitizedConfigJson;
                }
                else
                {
                    _session = null;
                    AppendLog("Initialisierung fehlgeschlagen. Prüfe Log für Details.", LogLevels.Error);
                }
            }
            catch (Exception ex)
            {
                _session = null;
                AppendLog($"Fehler bei Initialisierung: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "Initialisierung fehlgeschlagen", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                ToggleActionButtons(true);
            }
        }

        private void ToggleActionButtons(bool enabled)
        {
            InitializeButton.IsEnabled = enabled;
            LoadJsonButton.IsEnabled = enabled;
            ExportJsonButton.IsEnabled = enabled;
            var providerReady = enabled && _session?.Provider != null;
            FetchDataAreasButton.IsEnabled = providerReady;
            FetchSecurityGroupsButton.IsEnabled = providerReady;
            ActionsGroupBox.IsEnabled = providerReady;
            UpdateActionHint();
        }

        private void ProviderTypeCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_session?.Provider != null
                && ProviderTypeCombo.SelectedItem is eLiamProviderTypes providerType
                && _session.Provider.ProviderType != providerType)
            {
                _session = null;
                AppendLog("Provider-Typ gewechselt. Bitte Provider neu initialisieren, bevor Calls ausgeführt werden.", LogLevels.Warning);
            }

            UpdateProviderActionPanel();
            ToggleActionButtons(true);
            if (_isInitializingUi)
                return;
            SaveSettings();
        }

        private void ClearLogButton_Click(object sender, RoutedEventArgs e)
        {
            _logEntries.Clear();
            StatusTextBlock.Text = string.Empty;
            AppendLog("Log gelöscht.", LogLevels.Debug);
        }

        private void WhatIfCheckBox_Click(object sender, RoutedEventArgs e)
        {
            if (_isInitializingUi)
                return;

            UpdateActionHint();
            SaveSettings();
            AppendLog(IsWhatIfEnabled
                ? "WhatIf aktiviert. Schreibende Aktionen im Diagnostics Tool werden nur simuliert."
                : "WhatIf deaktiviert. Schreibende Aktionen im Diagnostics Tool werden real ausgeführt.", LogLevels.Warning);
        }

        private void LogListBox_KeyDown(object sender, KeyEventArgs e)
        {
            if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control)
                return;

            if (e.Key == Key.A)
            {
                LogListBox.SelectAll();
                e.Handled = true;
                return;
            }

            if (e.Key != Key.C)
                return;

            var selectedLines = LogListBox.SelectedItems
                .Cast<object>()
                .Select(i => i?.ToString() ?? string.Empty)
                .Where(i => !string.IsNullOrWhiteSpace(i))
                .ToList();

            if (selectedLines.Count == 0)
                return;

            Clipboard.SetText(string.Join(Environment.NewLine, selectedLines));
            AppendLog($"Logzeilen in Zwischenablage kopiert: {selectedLines.Count}", LogLevels.Debug);
            e.Handled = true;
        }

        private void LoadSettings()
        {
            ToolSettings settings = null;
            try
            {
                if (File.Exists(_settingsPath))
                {
                    var json = File.ReadAllText(_settingsPath, Encoding.UTF8);
                    settings = JsonConvert.DeserializeObject<ToolSettings>(json);
                }
            }
            catch (Exception ex)
            {
                AppendLog($"Einstellungen konnten nicht geladen werden: {ex.Message}", LogLevels.Warning);
            }

            if (settings == null)
            {
                settings = new ToolSettings();
            }
            ApplySettingsToUi(settings);
        }

        private void ApplySettingsToUi(ToolSettings settings)
        {
            if (settings == null)
                return;

            if (Enum.IsDefined(typeof(eLiamProviderTypes), settings.ProviderType))
                ProviderTypeCombo.SelectedItem = (eLiamProviderTypes)settings.ProviderType;

            DomainTextBox.Text = settings.Domain ?? string.Empty;
            RootPathTextBox.Text = settings.RootPath ?? string.Empty;
            MaxDepthTextBox.Text = string.IsNullOrWhiteSpace(settings.MaxDepth) ? "1" : settings.MaxDepth;
            GroupFilterTextBox.Text = settings.GroupFilter ?? string.Empty;
            GroupPathTextBox.Text = settings.GroupPath ?? string.Empty;
            DataAreaFilterTextBox.Text = settings.DataAreaFilter ?? string.Empty;
            DataAreaRegexTextBox.Text = settings.DataAreaRegex ?? string.Empty;
            GroupRegexTextBox.Text = settings.GroupRegex ?? string.Empty;
            TraverseGroupTextBox.Text = settings.TraverseGroup ?? string.Empty;
            OwnerGroupGlobalTextBox.Text = settings.OwnerGroupGlobal ?? string.Empty;
            OwnerGroupLocalTextBox.Text = settings.OwnerGroupLocal ?? string.Empty;
            WriteGroupGlobalTextBox.Text = settings.WriteGroupGlobal ?? string.Empty;
            WriteGroupLocalTextBox.Text = settings.WriteGroupLocal ?? string.Empty;
            ReadGroupGlobalTextBox.Text = settings.ReadGroupGlobal ?? string.Empty;
            ReadGroupLocalTextBox.Text = settings.ReadGroupLocal ?? string.Empty;
            CredentialUserTextBox.Text = settings.CredentialUser ?? string.Empty;
            CredentialDomainTextBox.Text = settings.CredentialDomain ?? string.Empty;
            MaskTokenTextBox.Text = settings.MaskToken ?? "***";
            AdditionalConfigTextBox.Text = settings.AdditionalConfiguration ?? string.Empty;
            CustomTagsTextBox.Text = settings.CustomTags ?? string.Empty;
            NamingConventionsTextBox.Text = settings.NamingConventions ?? string.Empty;
            RawJsonTextBox.Text = settings.RawJson ?? string.Empty;
            ProviderConfigIdTextBox.Text = settings.ProviderConfigClassId ?? string.Empty;
            ProviderConfigObjectIdTextBox.Text = settings.ProviderConfigObjectId ?? string.Empty;
            ServerNameTextBox.Text = settings.ServerName ?? string.Empty;
            UseHttpsCheckBox.IsChecked = settings.UseHttps;
            LicenseTextBox.Text = settings.License ?? string.Empty;
            WhatIfCheckBox.IsChecked = settings.EnableWhatIf;
            NtfsCreateFolderPathTextBox.Text = settings.NtfsCreateFolderPath ?? string.Empty;
            NtfsCreateParentPathTextBox.Text = settings.NtfsCreateParentPath ?? string.Empty;
            NtfsCreateOwnerSidsTextBox.Text = settings.NtfsCreateOwnerSids ?? string.Empty;
            NtfsCreateReaderSidsTextBox.Text = settings.NtfsCreateReaderSids ?? string.Empty;
            NtfsCreateWriterSidsTextBox.Text = settings.NtfsCreateWriterSids ?? string.Empty;
            NtfsEnsureFolderPathTextBox.Text = settings.NtfsEnsureFolderPath ?? string.Empty;
            NtfsEnsureOwnerSidsTextBox.Text = settings.NtfsEnsureOwnerSids ?? string.Empty;
            NtfsEnsureReaderSidsTextBox.Text = settings.NtfsEnsureReaderSids ?? string.Empty;
            NtfsEnsureWriterSidsTextBox.Text = settings.NtfsEnsureWriterSids ?? string.Empty;
            NtfsEnsureTraverseCheckBox.IsChecked = settings.NtfsEnsureTraverse;
            AdServiceNameTextBox.Text = settings.AdServiceName ?? string.Empty;
            AdDescriptionTextBox.Text = settings.AdDescription ?? string.Empty;
            AdOwnerSidsTextBox.Text = settings.AdOwnerSids ?? string.Empty;
            AdMemberSidsTextBox.Text = settings.AdMemberSids ?? string.Empty;
            MsTeamsSourceTeamIdTextBox.Text = settings.MsTeamsSourceTeamId ?? string.Empty;
            MsTeamsNewNameTextBox.Text = settings.MsTeamsNewName ?? string.Empty;
            MsTeamsDescriptionTextBox.Text = settings.MsTeamsDescription ?? string.Empty;
            MsTeamsCloneAppsCheckBox.IsChecked = settings.MsTeamsCloneApps;
            MsTeamsCloneTabsCheckBox.IsChecked = settings.MsTeamsCloneTabs;
            MsTeamsCloneSettingsCheckBox.IsChecked = settings.MsTeamsCloneSettings;
            MsTeamsCloneChannelsCheckBox.IsChecked = settings.MsTeamsCloneChannels;
            MsTeamsCloneMembersCheckBox.IsChecked = settings.MsTeamsCloneMembers;
            MsTeamsAdditionalMembersTextBox.Text = settings.MsTeamsAdditionalMembers ?? string.Empty;
            MsTeamsAdditionalOwnersTextBox.Text = settings.MsTeamsAdditionalOwners ?? string.Empty;
            ExchangeMailboxNameTextBox.Text = settings.ExchangeMailboxName ?? string.Empty;
            ExchangeMailboxAliasTextBox.Text = settings.ExchangeMailboxAlias ?? string.Empty;
            ExchangeMailboxDisplayNameTextBox.Text = settings.ExchangeMailboxDisplayName ?? string.Empty;
            ExchangeMailboxPrimarySmtpTextBox.Text = settings.ExchangeMailboxPrimarySmtp ?? string.Empty;
            ExchangeDistributionNameTextBox.Text = settings.ExchangeDistributionName ?? string.Empty;
            ExchangeDistributionAliasTextBox.Text = settings.ExchangeDistributionAlias ?? string.Empty;
            ExchangeDistributionDisplayNameTextBox.Text = settings.ExchangeDistributionDisplayName ?? string.Empty;
            ExchangeDistributionPrimarySmtpTextBox.Text = settings.ExchangeDistributionPrimarySmtp ?? string.Empty;

            if (Enum.IsDefined(typeof(eLiamGroupStrategies), settings.GroupStrategy))
                GroupStrategyCombo.SelectedItem = (eLiamGroupStrategies)settings.GroupStrategy;
            if (Enum.IsDefined(typeof(eLiamAccessRoleScopes), settings.AdScope))
                AdScopeComboBox.SelectedItem = (eLiamAccessRoleScopes)settings.AdScope;
            if (Enum.IsDefined(typeof(ADServiceGroupCreator.ADGroupType), settings.AdGroupType))
                AdGroupTypeComboBox.SelectedItem = (ADServiceGroupCreator.ADGroupType)settings.AdGroupType;
            MsTeamsVisibilityComboBox.SelectedValue = IsValidMsTeamsVisibility(settings.MsTeamsVisibility)
                ? settings.MsTeamsVisibility
                : MsTeamsVisibilityPrivate;
        }

        private void SaveSettings()
        {
            try
            {
                var settings = new ToolSettings
                {
                    ProviderType = ProviderTypeCombo.SelectedItem is eLiamProviderTypes type ? (int)type : (int)eLiamProviderTypes.MsTeams,
                    Domain = DomainTextBox.Text ?? string.Empty,
                    RootPath = RootPathTextBox.Text ?? string.Empty,
                    MaxDepth = MaxDepthTextBox.Text ?? string.Empty,
                    GroupFilter = GroupFilterTextBox.Text ?? string.Empty,
                    GroupPath = GroupPathTextBox.Text ?? string.Empty,
                    DataAreaFilter = DataAreaFilterTextBox.Text ?? string.Empty,
                    DataAreaRegex = DataAreaRegexTextBox.Text ?? string.Empty,
                    GroupRegex = GroupRegexTextBox.Text ?? string.Empty,
                    TraverseGroup = TraverseGroupTextBox.Text ?? string.Empty,
                    OwnerGroupGlobal = OwnerGroupGlobalTextBox.Text ?? string.Empty,
                    OwnerGroupLocal = OwnerGroupLocalTextBox.Text ?? string.Empty,
                    WriteGroupGlobal = WriteGroupGlobalTextBox.Text ?? string.Empty,
                    WriteGroupLocal = WriteGroupLocalTextBox.Text ?? string.Empty,
                    ReadGroupGlobal = ReadGroupGlobalTextBox.Text ?? string.Empty,
                    ReadGroupLocal = ReadGroupLocalTextBox.Text ?? string.Empty,
                    CredentialUser = CredentialUserTextBox.Text ?? string.Empty,
                    CredentialDomain = CredentialDomainTextBox.Text ?? string.Empty,
                    MaskToken = MaskTokenTextBox.Text ?? "***",
                    AdditionalConfiguration = AdditionalConfigTextBox.Text ?? string.Empty,
                    CustomTags = CustomTagsTextBox.Text ?? string.Empty,
                    NamingConventions = NamingConventionsTextBox.Text ?? string.Empty,
                    RawJson = RawJsonTextBox.Text ?? string.Empty,
                    ProviderConfigClassId = ProviderConfigIdTextBox.Text ?? string.Empty,
                    ProviderConfigObjectId = ProviderConfigObjectIdTextBox.Text ?? string.Empty,
                    ServerName = ServerNameTextBox.Text ?? string.Empty,
                    UseHttps = UseHttpsCheckBox.IsChecked ?? false,
                    License = LicenseTextBox.Text ?? string.Empty,
                    EnableWhatIf = WhatIfCheckBox.IsChecked ?? true,
                    GroupStrategy = GroupStrategyCombo.SelectedItem is eLiamGroupStrategies gs ? (int)gs : (int)eLiamGroupStrategies.Ntfs_AGDLP,
                    NtfsCreateFolderPath = NtfsCreateFolderPathTextBox.Text ?? string.Empty,
                    NtfsCreateParentPath = NtfsCreateParentPathTextBox.Text ?? string.Empty,
                    NtfsCreateOwnerSids = NtfsCreateOwnerSidsTextBox.Text ?? string.Empty,
                    NtfsCreateReaderSids = NtfsCreateReaderSidsTextBox.Text ?? string.Empty,
                    NtfsCreateWriterSids = NtfsCreateWriterSidsTextBox.Text ?? string.Empty,
                    NtfsEnsureFolderPath = NtfsEnsureFolderPathTextBox.Text ?? string.Empty,
                    NtfsEnsureOwnerSids = NtfsEnsureOwnerSidsTextBox.Text ?? string.Empty,
                    NtfsEnsureReaderSids = NtfsEnsureReaderSidsTextBox.Text ?? string.Empty,
                    NtfsEnsureWriterSids = NtfsEnsureWriterSidsTextBox.Text ?? string.Empty,
                    NtfsEnsureTraverse = NtfsEnsureTraverseCheckBox.IsChecked ?? false,
                    AdServiceName = AdServiceNameTextBox.Text ?? string.Empty,
                    AdDescription = AdDescriptionTextBox.Text ?? string.Empty,
                    AdScope = AdScopeComboBox.SelectedItem is eLiamAccessRoleScopes scope ? (int)scope : (int)eLiamAccessRoleScopes.Universal,
                    AdGroupType = AdGroupTypeComboBox.SelectedItem is ADServiceGroupCreator.ADGroupType groupType ? (int)groupType : (int)ADServiceGroupCreator.ADGroupType.Distribution,
                    AdOwnerSids = AdOwnerSidsTextBox.Text ?? string.Empty,
                    AdMemberSids = AdMemberSidsTextBox.Text ?? string.Empty,
                    MsTeamsSourceTeamId = MsTeamsSourceTeamIdTextBox.Text ?? string.Empty,
                    MsTeamsNewName = MsTeamsNewNameTextBox.Text ?? string.Empty,
                    MsTeamsDescription = MsTeamsDescriptionTextBox.Text ?? string.Empty,
                    MsTeamsVisibility = GetSelectedMsTeamsVisibility(),
                    MsTeamsCloneApps = MsTeamsCloneAppsCheckBox.IsChecked ?? false,
                    MsTeamsCloneTabs = MsTeamsCloneTabsCheckBox.IsChecked ?? false,
                    MsTeamsCloneSettings = MsTeamsCloneSettingsCheckBox.IsChecked ?? true,
                    MsTeamsCloneChannels = MsTeamsCloneChannelsCheckBox.IsChecked ?? true,
                    MsTeamsCloneMembers = MsTeamsCloneMembersCheckBox.IsChecked ?? false,
                    MsTeamsAdditionalMembers = MsTeamsAdditionalMembersTextBox.Text ?? string.Empty,
                    MsTeamsAdditionalOwners = MsTeamsAdditionalOwnersTextBox.Text ?? string.Empty,
                    ExchangeMailboxName = ExchangeMailboxNameTextBox.Text ?? string.Empty,
                    ExchangeMailboxAlias = ExchangeMailboxAliasTextBox.Text ?? string.Empty,
                    ExchangeMailboxDisplayName = ExchangeMailboxDisplayNameTextBox.Text ?? string.Empty,
                    ExchangeMailboxPrimarySmtp = ExchangeMailboxPrimarySmtpTextBox.Text ?? string.Empty,
                    ExchangeDistributionName = ExchangeDistributionNameTextBox.Text ?? string.Empty,
                    ExchangeDistributionAlias = ExchangeDistributionAliasTextBox.Text ?? string.Empty,
                    ExchangeDistributionDisplayName = ExchangeDistributionDisplayNameTextBox.Text ?? string.Empty,
                    ExchangeDistributionPrimarySmtp = ExchangeDistributionPrimarySmtpTextBox.Text ?? string.Empty
                };

                var directory = Path.GetDirectoryName(_settingsPath);
                if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                    Directory.CreateDirectory(directory);

                var json = JsonConvert.SerializeObject(settings, Formatting.Indented);
                File.WriteAllText(_settingsPath, json, Encoding.UTF8);
            }
            catch (Exception ex)
            {
                AppendLog($"Einstellungen konnten nicht gespeichert werden: {ex.Message}", LogLevels.Warning);
            }
        }

        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            SaveSettings();
        }

        private void UpdateProviderActionPanel()
        {
            NtfsActionPanel.Visibility = Visibility.Collapsed;
            AdActionPanel.Visibility = Visibility.Collapsed;
            MsTeamsActionPanel.Visibility = Visibility.Collapsed;
            ExchangeActionPanel.Visibility = Visibility.Collapsed;

            if (!(ProviderTypeCombo.SelectedItem is eLiamProviderTypes providerType))
            {
                UpdateActionHint();
                return;
            }

            switch (providerType)
            {
                case eLiamProviderTypes.Ntfs:
                    NtfsActionPanel.Visibility = Visibility.Visible;
                    break;
                case eLiamProviderTypes.ActiveDirectory:
                    AdActionPanel.Visibility = Visibility.Visible;
                    break;
                case eLiamProviderTypes.MsTeams:
                    MsTeamsActionPanel.Visibility = Visibility.Visible;
                    break;
                case eLiamProviderTypes.Exchange:
                    ExchangeActionPanel.Visibility = Visibility.Visible;
                    break;
            }

            UpdateActionHint();
        }

        private void UpdateActionHint()
        {
            if (!(ProviderTypeCombo.SelectedItem is eLiamProviderTypes providerType))
            {
                ActionHintTextBlock.Text = "Waehle einen Provider-Typ aus.";
                return;
            }

            var providerReady = _session?.Provider != null;
            var providerHint = string.Empty;
            switch (providerType)
            {
                case eLiamProviderTypes.Ntfs:
                    providerHint = "NTFS: neue Ordner anlegen oder auf bestehenden Ordnern fehlende Berechtigungsgruppen und ACLs additiv sicherstellen.";
                    break;
                case eLiamProviderTypes.ActiveDirectory:
                    providerHint = "Active Directory: Owner- und Member-Gruppen fuer einen Service anhand der konfigurierten Namenskonvention sicherstellen.";
                    break;
                case eLiamProviderTypes.MsTeams:
                    providerHint = "Microsoft Teams: Team-Clone mit steuerbaren Clone-Bestandteilen ausfuehren.";
                    break;
                case eLiamProviderTypes.Exchange:
                    providerHint = "Exchange: Shared Mailbox oder Distribution Group inklusive Ownership-Gruppen erzeugen.";
                    break;
                default:
                    providerHint = "Fuer diesen Provider sind keine Anlage-Aktionen hinterlegt.";
                    break;
            }

            var modeHint = IsWhatIfEnabled
                ? " WhatIf ist aktiv: Schreibende Diagnostics-Aktionen werden nur simuliert."
                : " WhatIf ist deaktiviert: Schreibende Diagnostics-Aktionen werden real ausgeführt.";

            ActionHintTextBlock.Text = providerReady
                ? providerHint + modeHint
                : $"Initialisiere zuerst einen Provider. {providerHint}{modeHint}";
        }

        private async void FetchDataAreasButton_Click(object sender, RoutedEventArgs e)
        {
            if (_session?.Provider == null)
            {
                AppendLog("Kein Provider initialisiert.", LogLevels.Warning);
                return;
            }

            try
            {
                var provider = _session.Provider;
                var configurationId = !string.IsNullOrWhiteSpace(_session.ProviderConfigObjectId)
                    ? _session.ProviderConfigObjectId
                    : (_session.ProviderConfigId ?? string.Empty);
                var runWhatIf = IsWhatIfEnabled;
                var maxDepth = provider.MaxDepth;
                AppendLog($"Lese DataAreas (MaxDepth={maxDepth}) ...");
                var result = await Task.Run(() => LiamWorkflowRuntime.GetDataAreasFromProviderAsync(
                    provider,
                    configurationId,
                    runWhatIf));
                ResultTextBox.Text = JsonConvert.SerializeObject(result, Formatting.Indented);

                if (!result.Success)
                {
                    AppendLog($"DataAreas-Call fehlgeschlagen [{result.ErrorCode}]: {result.ErrorMessage}", LogLevels.Error);
                    return;
                }

                if (result.DataAreas.Count == 0)
                {
                    AppendLog("Keine DataAreas gefunden.", LogLevels.Warning);
                    return;
                }

                if (runWhatIf && result.AutomaticEnsurePreview != null && result.AutomaticEnsurePreview.Count > 0)
                {
                    AppendLog($"EnsureNtfsPermissionGroups wurde nur simuliert fuer {result.AutomaticEnsurePreview.Count} Ordner. Details stehen im Result-JSON.", LogLevels.Warning);
                }

                AppendLog($"DataAreas erhalten: {result.DataAreas.Count}");
            }
            catch (Exception ex)
            {
                AppendLog($"Fehler beim Laden der DataAreas: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "Fehler beim DataArea-Call", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void ExecuteNtfsCreateButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var provider = EnsureInitializedProvider<cLiamProviderNtfs>("NTFS");
                var folderPath = GetRequiredText(NtfsCreateFolderPathTextBox.Text, "New Folder Path");
                var parentPath = NormalizeOptionalText(NtfsCreateParentPathTextBox.Text);
                if (string.IsNullOrWhiteSpace(parentPath))
                {
                    parentPath = Directory.GetParent(folderPath)?.FullName;
                }
                if (string.IsNullOrWhiteSpace(parentPath))
                    throw new InvalidOperationException("Parent Folder Path konnte nicht ermittelt werden.");
                var ownerSids = ParseIdentifierList(NtfsCreateOwnerSidsTextBox.Text, "Owner SIDs");
                if (ownerSids.Count == 0)
                    throw new InvalidOperationException("Owner SIDs: mindestens ein Eintrag ist fuer die Ordneranlage erforderlich.");
                var readerSids = ParseIdentifierList(NtfsCreateReaderSidsTextBox.Text, "Reader SIDs");
                var writerSids = ParseIdentifierList(NtfsCreateWriterSidsTextBox.Text, "Writer SIDs");

                await ExecuteProviderActionAsync("NTFS Folder Create", async () =>
                {
                    var result = await Task.Run(() => LiamWorkflowRuntime.CreateDataAreaAsync(
                        provider,
                        folderPath,
                        parentPath,
                        null,
                        ownerSids,
                        readerSids,
                        writerSids));

                    return new
                    {
                        result.Success,
                        ResultToken = MapResultToken(result.ResultToken)
                    };
                }, () =>
                {
                    return CreateWhatIfResult(
                        "NTFS Folder Create",
                        "Wuerde einen Ordner anlegen und fehlende Gruppen sowie ACLs sicherstellen. Es wurden keine Aenderungen ausgefuehrt.",
                        new
                        {
                            ProviderRootPath = provider.RootPath,
                            NewFolderPath = folderPath,
                            ParentFolderPath = parentPath,
                            OwnerSids = ownerSids,
                            ReaderSids = readerSids,
                            WriterSids = writerSids
                        });
                });
            }
            catch (Exception ex)
            {
                AppendLog($"NTFS Folder Create fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "NTFS Folder Create", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void ExecuteNtfsEnsureButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var provider = EnsureInitializedProvider<cLiamProviderNtfs>("NTFS");
                var folderPath = GetRequiredText(NtfsEnsureFolderPathTextBox.Text, "Folder Path");
                var ownerSids = ParseIdentifierList(NtfsEnsureOwnerSidsTextBox.Text, "Owner SIDs");
                var readerSids = ParseIdentifierList(NtfsEnsureReaderSidsTextBox.Text, "Reader SIDs");
                var writerSids = ParseIdentifierList(NtfsEnsureWriterSidsTextBox.Text, "Writer SIDs");
                var ensureTraverse = NtfsEnsureTraverseCheckBox.IsChecked ?? false;

                await ExecuteProviderActionAsync("NTFS Ensure Groups / ACLs", async () =>
                {
                    var result = await Task.Run(() => LiamWorkflowRuntime.EnsureNtfsPermissionGroupsAsync(
                        provider,
                        folderPath,
                        null,
                        ownerSids,
                        readerSids,
                        writerSids,
                        ensureTraverse));

                    return new
                    {
                        result.Success,
                        ResultToken = MapResultToken(result.ResultToken)
                    };
                }, () =>
                {
                    return CreateWhatIfResult(
                        "NTFS Ensure Groups / ACLs",
                        "Wuerde fehlende NTFS-Berechtigungsgruppen und ACLs additiv sicherstellen. Es wurden keine Aenderungen ausgefuehrt.",
                        new
                        {
                            ProviderRootPath = provider.RootPath,
                            FolderPath = folderPath,
                            OwnerSids = ownerSids,
                            ReaderSids = readerSids,
                            WriterSids = writerSids,
                            EnsureTraverseGroups = ensureTraverse
                        });
                });
            }
            catch (Exception ex)
            {
                AppendLog($"NTFS Ensure Groups / ACLs fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "NTFS Ensure Groups / ACLs", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void ExecuteAdCreateButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var provider = EnsureInitializedProvider<cLiamProviderAD>("Active Directory");
                var serviceName = GetRequiredText(AdServiceNameTextBox.Text, "Service Name");
                var description = NormalizeOptionalText(AdDescriptionTextBox.Text);
                var scope = AdScopeComboBox.SelectedItem is eLiamAccessRoleScopes selectedScope
                    ? selectedScope
                    : eLiamAccessRoleScopes.Universal;
                var groupType = AdGroupTypeComboBox.SelectedItem is ADServiceGroupCreator.ADGroupType selectedType
                    ? selectedType
                    : ADServiceGroupCreator.ADGroupType.Distribution;
                var ownerSids = ParseIdentifierList(AdOwnerSidsTextBox.Text, "Owner SIDs");
                var memberSids = ParseIdentifierList(AdMemberSidsTextBox.Text, "Member SIDs");

                await ExecuteProviderActionAsync("AD Ensure Service Groups", async () =>
                {
                    var result = await Task.Run(() => LiamWorkflowRuntime.CreateAdServiceGroups(
                        provider,
                        serviceName,
                        description,
                        scope,
                        groupType,
                        ownerSids,
                        memberSids));

                    return result;
                }, () =>
                {
                    return CreateWhatIfResult(
                        "AD Ensure Service Groups",
                        "Wuerde Service-Gruppen im Active Directory anhand der Namenskonvention sicherstellen. Es wurden keine Aenderungen ausgefuehrt.",
                        new
                        {
                            ServiceName = serviceName,
                            Description = description,
                            Scope = scope.ToString(),
                            GroupType = groupType.ToString(),
                            OwnerSids = ownerSids,
                            MemberSids = memberSids
                        });
                });
            }
            catch (Exception ex)
            {
                AppendLog($"AD Ensure Service Groups fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "AD Ensure Service Groups", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void ExecuteMsTeamsCloneButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var provider = EnsureInitializedProvider<cLiamProviderMsTeams>("MsTeams");
                var sourceTeamId = GetRequiredText(MsTeamsSourceTeamIdTextBox.Text, "Source Team ID");
                var newTeamName = GetRequiredText(MsTeamsNewNameTextBox.Text, "New Team Name");
                var description = NormalizeOptionalText(MsTeamsDescriptionTextBox.Text);
                var visibility = GetSelectedMsTeamsVisibility();
                var partsToClone = GetSelectedCloneParts();
                var additionalMembers = ParseIdentifierList(MsTeamsAdditionalMembersTextBox.Text, "Additional Members");
                var additionalOwners = ParseIdentifierList(MsTeamsAdditionalOwnersTextBox.Text, "Additional Owners");

                await ExecuteProviderActionAsync("MsTeams Clone Team", async () =>
                {
                    var result = await Task.Run(() => LiamWorkflowRuntime.CloneTeamAsync(
                        provider,
                        sourceTeamId,
                        newTeamName,
                        description,
                        visibility,
                        partsToClone,
                        string.Join(";", additionalMembers),
                        string.Join(";", additionalOwners)));

                    return result;
                }, () =>
                {
                    return CreateWhatIfResult(
                        "MsTeams Clone Team",
                        "Wuerde ein Team anhand der gewaehlten Clone-Bestandteile klonen. Es wurden keine Aenderungen ausgefuehrt.",
                        new
                        {
                            SourceTeamId = sourceTeamId,
                            NewTeamName = newTeamName,
                            Description = description,
                            Visibility = visibility,
                            PartsToClone = partsToClone,
                            AdditionalMembers = additionalMembers,
                            AdditionalOwners = additionalOwners
                        });
                });
            }
            catch (Exception ex)
            {
                AppendLog($"MsTeams Clone Team fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "MsTeams Clone Team", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void ExecuteExchangeMailboxButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var provider = EnsureInitializedProvider<cLiamProviderExchange>("Exchange");
                var name = GetRequiredText(ExchangeMailboxNameTextBox.Text, "Name");
                var alias = GetRequiredText(ExchangeMailboxAliasTextBox.Text, "Alias");
                var displayName = NormalizeOptionalText(ExchangeMailboxDisplayNameTextBox.Text);
                var primarySmtp = NormalizeOptionalText(ExchangeMailboxPrimarySmtpTextBox.Text);

                await ExecuteProviderActionAsync("Exchange Create Shared Mailbox", async () =>
                {
                    var result = await Task.Run(() => LiamWorkflowRuntime.CreateSharedMailbox(
                        provider,
                        name,
                        alias,
                        displayName,
                        primarySmtp));

                    return result;
                }, () =>
                {
                    return CreateWhatIfResult(
                        "Exchange Create Shared Mailbox",
                        "Wuerde eine Shared Mailbox inklusive Ownership-Gruppen erzeugen. Es wurden keine Aenderungen ausgefuehrt.",
                        new
                        {
                            Name = name,
                            Alias = alias,
                            DisplayName = displayName,
                            PrimarySmtpAddress = primarySmtp
                        });
                });
            }
            catch (Exception ex)
            {
                AppendLog($"Exchange Create Shared Mailbox fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "Exchange Create Shared Mailbox", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void ExecuteExchangeDistributionButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var provider = EnsureInitializedProvider<cLiamProviderExchange>("Exchange");
                var name = GetRequiredText(ExchangeDistributionNameTextBox.Text, "Name");
                var alias = GetRequiredText(ExchangeDistributionAliasTextBox.Text, "Alias");
                var displayName = NormalizeOptionalText(ExchangeDistributionDisplayNameTextBox.Text);
                var primarySmtp = NormalizeOptionalText(ExchangeDistributionPrimarySmtpTextBox.Text);

                await ExecuteProviderActionAsync("Exchange Create Distribution Group", async () =>
                {
                    var result = await Task.Run(() => LiamWorkflowRuntime.CreateDistributionGroup(
                        provider,
                        name,
                        alias,
                        displayName,
                        primarySmtp));

                    return result;
                }, () =>
                {
                    return CreateWhatIfResult(
                        "Exchange Create Distribution Group",
                        "Wuerde eine Distribution Group inklusive Ownership-Gruppen erzeugen. Es wurden keine Aenderungen ausgefuehrt.",
                        new
                        {
                            Name = name,
                            Alias = alias,
                            DisplayName = displayName,
                            PrimarySmtpAddress = primarySmtp
                        });
                });
            }
            catch (Exception ex)
            {
                AppendLog($"Exchange Create Distribution Group fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "Exchange Create Distribution Group", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async void FetchSecurityGroupsButton_Click(object sender, RoutedEventArgs e)
        {
            if (_session?.Provider == null)
            {
                AppendLog("Kein Provider initialisiert.", LogLevels.Warning);
                return;
            }

            try
            {
                var provider = _session.Provider;
                var filter = provider.GroupFilter;
                AppendLog($"Lese SecurityGroups (Filter='{filter}') ...");
                var result = await Task.Run(() => LiamWorkflowRuntime.GetSecurityGroupsFromProviderAsync(provider));
                ResultTextBox.Text = JsonConvert.SerializeObject(result, Formatting.Indented);

                if (!result.Success)
                {
                    AppendLog($"SecurityGroups-Call fehlgeschlagen [{result.ErrorCode}]: {result.ErrorMessage}", LogLevels.Error);
                    return;
                }

                if (result.SecurityGroups.Count == 0)
                {
                    AppendLog("Keine SecurityGroups gefunden.", LogLevels.Warning);
                    return;
                }

                AppendLog($"SecurityGroups erhalten: {result.SecurityGroups.Count}");
            }
            catch (Exception ex)
            {
                AppendLog($"Fehler beim Laden der SecurityGroups: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "Fehler beim SecurityGroup-Call", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void LoadJsonButton_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(RawJsonTextBox.Text))
            {
                AppendLog("Kein JSON zum Laden vorhanden.", LogLevels.Warning);
                return;
            }

            try
            {
                var data = ParseProviderDataFromInput(RawJsonTextBox.Text);
                if (data == null)
                {
                    AppendLog("JSON enthielt keine gültigen Providerdaten.", LogLevels.Error);
                    return;
                }
                PopulateFields(data);
                AppendLog("Providerdaten aus JSON übernommen.");
            }
            catch (Exception ex)
            {
                AppendLog($"JSON konnte nicht geparst werden: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "JSON-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private async Task ExecuteProviderActionAsync(string actionName, Func<Task<object>> action, Func<object> whatIfAction = null)
        {
            if (action == null)
                throw new ArgumentNullException(nameof(action));

            ToggleActionButtons(false);
            try
            {
                SaveSettings();
                var runInWhatIfMode = IsWhatIfEnabled && whatIfAction != null;
                AppendLog(runInWhatIfMode
                    ? $"{actionName} im WhatIf-Modus gestartet. Schreibende Aenderungen werden nur simuliert."
                    : $"{actionName} gestartet.");
                var result = runInWhatIfMode
                    ? await Task.Run(whatIfAction)
                    : await action();
                ResultTextBox.Text = JsonConvert.SerializeObject(result, Formatting.Indented);
                if (TryGetSuccessFlag(result, out var success) && !success)
                    AppendLog($"{actionName} mit Fehlerstatus abgeschlossen.", LogLevels.Warning);
                else if (runInWhatIfMode)
                    AppendLog($"{actionName} im WhatIf-Modus simuliert abgeschlossen.", LogLevels.Warning);
                else
                    AppendLog($"{actionName} erfolgreich abgeschlossen.");
            }
            catch (Exception ex)
            {
                AppendLog($"{actionName} fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), actionName, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                ToggleActionButtons(true);
            }
        }

        private bool TryGetSuccessFlag(object instance, out bool success)
        {
            success = false;
            if (instance == null)
                return false;

            var property = instance.GetType().GetProperty("Success", BindingFlags.Instance | BindingFlags.Public);
            if (property == null || property.PropertyType != typeof(bool))
                return false;

            var rawValue = property.GetValue(instance);
            if (!(rawValue is bool boolValue))
                return false;

            success = boolValue;
            return true;
        }

        private bool IsWhatIfEnabled => WhatIfCheckBox.IsChecked ?? true;

        private object CreateWhatIfResult(string actionName, string message, object input)
        {
            return new
            {
                Success = true,
                WhatIf = true,
                Operation = actionName,
                Message = message ?? string.Empty,
                TimestampUtc = DateTime.UtcNow.ToString("s") + "Z",
                Input = input
            };
        }

        private TProvider EnsureInitializedProvider<TProvider>(string providerName) where TProvider : cLiamProviderBase
        {
            if (_session?.Provider == null)
                throw new InvalidOperationException("Bitte zuerst den Provider initialisieren.");

            if (!(_session.Provider is TProvider provider))
                throw new InvalidOperationException($"Der initialisierte Provider ist nicht vom Typ '{providerName}'. Bitte Einstellungen pruefen und neu initialisieren.");

            return provider;
        }

        private List<string> ParseIdentifierList(string text, string context)
        {
            if (string.IsNullOrWhiteSpace(text))
                return new List<string>();

            var trimmed = text.Trim();
            if (trimmed.StartsWith("[", StringComparison.Ordinal))
            {
                try
                {
                    var array = JArray.Parse(trimmed);
                    return array.Values<string>()
                        .Where(i => !string.IsNullOrWhiteSpace(i))
                        .Select(i => i.Trim())
                        .Distinct(StringComparer.OrdinalIgnoreCase)
                        .ToList();
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException($"{context}: JSON-Array konnte nicht gelesen werden. {ex.Message}");
                }
            }

            return trimmed
                .Split(new[] { '\r', '\n', ';', ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(i => i.Trim())
                .Where(i => !string.IsNullOrWhiteSpace(i))
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .ToList();
        }

        private string GetRequiredText(string value, string fieldName)
        {
            var trimmed = NormalizeOptionalText(value);
            if (string.IsNullOrWhiteSpace(trimmed))
                throw new InvalidOperationException($"{fieldName} ist erforderlich.");
            return trimmed;
        }

        private string NormalizeOptionalText(string value)
        {
            var trimmed = value?.Trim();
            return string.IsNullOrWhiteSpace(trimmed) ? null : trimmed;
        }

        private int GetSelectedCloneParts()
        {
            var parts = 0;
            if (MsTeamsCloneAppsCheckBox.IsChecked ?? false)
                parts |= MsTeamsCloneAppsFlag;
            if (MsTeamsCloneTabsCheckBox.IsChecked ?? false)
                parts |= MsTeamsCloneTabsFlag;
            if (MsTeamsCloneSettingsCheckBox.IsChecked ?? false)
                parts |= MsTeamsCloneSettingsFlag;
            if (MsTeamsCloneChannelsCheckBox.IsChecked ?? false)
                parts |= MsTeamsCloneChannelsFlag;
            if (MsTeamsCloneMembersCheckBox.IsChecked ?? false)
                parts |= MsTeamsCloneMembersFlag;
            return parts;
        }

        private object MapResultToken(ResultToken token)
        {
            if (token == null)
                return null;

            return new
            {
                Function = token.resultFunction ?? string.Empty,
                Message = token.resultMessage ?? string.Empty,
                ErrorId = token.resultErrorId,
                CreatedGroups = token.createdGroups ?? new List<string>(),
                ReusedGroups = token.reusedGroups ?? new List<string>(),
                AddedAclEntries = token.addedAclEntries ?? new List<string>(),
                SkippedAclEntries = token.skippedAclEntries ?? new List<string>(),
                EnsuredTraverseGroups = token.ensuredTraverseGroups ?? new List<string>(),
                Warnings = token.warnings ?? new List<string>()
            };
        }

        private int GetSelectedMsTeamsVisibility()
        {
            var selectedValue = MsTeamsVisibilityComboBox.SelectedValue;
            if (selectedValue is int intValue && IsValidMsTeamsVisibility(intValue))
                return intValue;

            if (selectedValue != null && int.TryParse(selectedValue.ToString(), out var parsedValue) && IsValidMsTeamsVisibility(parsedValue))
                return parsedValue;

            return MsTeamsVisibilityPrivate;
        }

        private bool IsValidMsTeamsVisibility(int value)
        {
            return value == MsTeamsVisibilityPrivate
                || value == MsTeamsVisibilityPublic
                || value == MsTeamsVisibilityHiddenMembership;
        }

        private cLiamProviderData ParseProviderDataFromInput(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
                return null;

            try
            {
                var token = JToken.Parse(input);
                return ParseProviderDataFromToken(token);
            }
            catch (JsonReaderException)
            {
                // Fallback: direkter Versuch, falls nur der reine Provider-Datensatz eingegeben wurde.
                return JsonConvert.DeserializeObject<cLiamProviderData>(input);
            }
        }

        private cLiamProviderData ParseProviderDataFromToken(JToken token)
        {
            if (token == null)
                return null;

            switch (token.Type)
            {
                case JTokenType.Object:
                    var obj = (JObject)token;

                    SetProviderIdentifiersFromObject(obj);

                    // Wenn der Export-Endpunkt verwendet wurde, liegt die Konfiguration im Feld "configuration".
                    var configurationProperty = obj.Properties()
                        .FirstOrDefault(p => string.Equals(p.Name, "configuration", StringComparison.OrdinalIgnoreCase));
                    if (configurationProperty != null)
                    {
                        var configToken = configurationProperty.Value;
                        var provider = configToken?.ToObject<cLiamProviderData>();
                        if (provider == null)
                            return null;

                        var sanitizedProperty = obj.Properties()
                            .FirstOrDefault(p => string.Equals(p.Name, "sanitizedJson", StringComparison.OrdinalIgnoreCase));
                        if (sanitizedProperty?.Value != null && sanitizedProperty.Value.Type == JTokenType.String)
                        {
                            var sanitized = sanitizedProperty.Value.Value<string>();
                            if (!string.IsNullOrWhiteSpace(sanitized))
                                RawJsonTextBox.Text = sanitized;
                        }
                        else
                        {
                            RawJsonTextBox.Text = JsonConvert.SerializeObject(provider, Formatting.Indented);
                        }

                        return provider;
                    }

                    // Alternativ: ein Objekt mit direkt eingebettetem Sanitized JSON.
                    var sanitizedJsonProperty = obj.Properties()
                        .FirstOrDefault(p => string.Equals(p.Name, "sanitizedJson", StringComparison.OrdinalIgnoreCase));
                    if (sanitizedJsonProperty?.Value != null)
                    {
                        var sanitized = sanitizedJsonProperty.Value.Type == JTokenType.String
                            ? sanitizedJsonProperty.Value.Value<string>()
                            : sanitizedJsonProperty.Value.ToString();

                        if (!string.IsNullOrWhiteSpace(sanitized))
                        {
                            RawJsonTextBox.Text = sanitized;
                            return JsonConvert.DeserializeObject<cLiamProviderData>(sanitized);
                        }
                    }

                    // Wenn nichts davon zutrifft, versuchen wir das Objekt direkt zu konvertieren.
                    var direct = obj.ToObject<cLiamProviderData>();
                    if (direct != null)
                        RawJsonTextBox.Text = JsonConvert.SerializeObject(direct, Formatting.Indented);
                    return direct;

                case JTokenType.String:
                    var json = token.Value<string>();
                    if (string.IsNullOrWhiteSpace(json))
                        return null;
                    RawJsonTextBox.Text = json;
                    return JsonConvert.DeserializeObject<cLiamProviderData>(json);

                default:
                    return token.ToObject<cLiamProviderData>();
            }
        }

        private void SetProviderIdentifiersFromObject(JObject obj)
        {
            if (obj == null)
                return;

            var classIdProp = obj.Properties().FirstOrDefault(p => string.Equals(p.Name, "providerconfigclassid", StringComparison.OrdinalIgnoreCase));
            if (classIdProp?.Value != null)
            {
                var value = classIdProp.Value.Type == JTokenType.String ? classIdProp.Value.Value<string>() : classIdProp.Value.ToString();
                ProviderConfigIdTextBox.Text = value?.Trim();
            }

            var objectIdProp = obj.Properties().FirstOrDefault(p => string.Equals(p.Name, "providerconfigobjectid", StringComparison.OrdinalIgnoreCase));
            if (objectIdProp?.Value != null)
            {
                var value = objectIdProp.Value.Type == JTokenType.String ? objectIdProp.Value.Value<string>() : objectIdProp.Value.ToString();
                ProviderConfigObjectIdTextBox.Text = value?.Trim();
            }
        }

        private void ExportJsonButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var providerData = BuildProviderDataFromFields();
                var maskToken = string.IsNullOrWhiteSpace(MaskTokenTextBox.Text) ? "***" : MaskTokenTextBox.Text.Trim();
                var sanitized = ProviderTestSession.BuildSanitizedJson(providerData, maskToken);
                ResultTextBox.Text = sanitized;
                AppendLog("Provider-Konfiguration als sanitisiertes JSON exportiert.");
            }
            catch (Exception ex)
            {
                AppendLog($"Export fehlgeschlagen: {ex.Message}", LogLevels.Error);
                MessageBox.Show(this, ex.ToString(), "Export-Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private cLiamProviderBase CreateProviderInstance(cLiamProviderData data)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));

            data.ReplaceCustomTags();
            var configuration = new cLiamConfiguration();

            switch (data.ProviderType)
            {
                case eLiamProviderTypes.MsTeams:
                    return new cLiamProviderMsTeams(configuration, data);
                case eLiamProviderTypes.Ntfs:
                    return new cLiamProviderNtfs(configuration, data);
                case eLiamProviderTypes.ActiveDirectory:
                    return new cLiamProviderAD(configuration, data);
                case eLiamProviderTypes.Exchange:
                    return new cLiamProviderExchange(configuration, data);
                default:
                    throw new NotSupportedException($"ProviderType '{data.ProviderType}' wird nicht unterstützt.");
            }
        }

        private cLiamProviderData BuildProviderDataFromFields()
        {
            if (!(ProviderTypeCombo.SelectedItem is eLiamProviderTypes providerType) || providerType == eLiamProviderTypes.Unknown)
                throw new InvalidOperationException("Bitte einen Provider-Typ auswählen.");

            var additional = ParseKeyValueLines(AdditionalConfigTextBox.Text, "Additional Configuration");
            var customTags = ParseKeyValueLines(CustomTagsTextBox.Text, "Custom Tags");
            var namingConventions = ParseNamingConventions(NamingConventionsTextBox.Text);

            var password = CredentialPasswordBox.Password ?? string.Empty;
            var credentialDomain = string.IsNullOrWhiteSpace(CredentialDomainTextBox.Text)
                ? DomainTextBox.Text?.Trim()
                : CredentialDomainTextBox.Text.Trim();

            if (string.IsNullOrWhiteSpace(password))
                throw new InvalidOperationException("Bitte ein Kennwort für den Logon hinterlegen.");

            var data = new cLiamProviderData
            {
                ProviderType = providerType,
                Domain = DomainTextBox.Text?.Trim() ?? string.Empty,
                RootPath = RootPathTextBox.Text?.Trim() ?? string.Empty,
                MaxDepth = ParseInt(MaxDepthTextBox.Text, 1),
                GroupFilter = GroupFilterTextBox.Text?.Trim() ?? string.Empty,
                GroupPath = GroupPathTextBox.Text?.Trim() ?? string.Empty,
                GroupStrategy = GroupStrategyCombo.SelectedItem is eLiamGroupStrategies gs ? gs : eLiamGroupStrategies.None,
                DataAreaFilter = DataAreaFilterTextBox.Text?.Trim() ?? string.Empty,
                DataAreaRegEx = DataAreaRegexTextBox.Text?.Trim() ?? string.Empty,
                GroupRegEx = GroupRegexTextBox.Text?.Trim() ?? string.Empty,
                TraverseGroup = TraverseGroupTextBox.Text?.Trim() ?? string.Empty,
                OwnerGroupGlobal = OwnerGroupGlobalTextBox.Text?.Trim() ?? string.Empty,
                OwnerGroupLocal = OwnerGroupLocalTextBox.Text?.Trim() ?? string.Empty,
                WriteGroupGlobal = WriteGroupGlobalTextBox.Text?.Trim() ?? string.Empty,
                WriteGroupLocal = WriteGroupLocalTextBox.Text?.Trim() ?? string.Empty,
                ReadGroupGlobal = ReadGroupGlobalTextBox.Text?.Trim() ?? string.Empty,
                ReadGroupLocal = ReadGroupLocalTextBox.Text?.Trim() ?? string.Empty,
                Credential = new cLiamCredential
                {
                    Domain = credentialDomain ?? string.Empty,
                    Identification = CredentialUserTextBox.Text?.Trim() ?? string.Empty,
                    Secret = password
                },
                AdditionalConfiguration = additional,
                CustomTags = customTags,
                NamingConventions = namingConventions
            };

            if (string.IsNullOrWhiteSpace(data.Credential.Identification))
                throw new InvalidOperationException("Bitte ein Konto für den Logon hinterlegen.");

            SaveSettings();

            return data;
        }

        private Dictionary<string, string> ParseKeyValueLines(string text, string context)
        {
            var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            if (string.IsNullOrWhiteSpace(text))
                return result;

            var lines = text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var line in lines)
            {
                var trimmed = line.Trim();
                if (trimmed.Length == 0 || trimmed.StartsWith("#"))
                    continue;

                var parts = trimmed.Split(new[] { '=' }, 2);
                if (parts.Length != 2)
                    throw new InvalidOperationException($"{context}: Ungültige Zeile '{line}'. Verwende Format key=value.");

                result[parts[0].Trim()] = parts[1].Trim();
            }

            return result;
        }

        private List<cLiamNamingConvention> ParseNamingConventions(string text)
        {
            if (string.IsNullOrWhiteSpace(text))
                return new List<cLiamNamingConvention>();

            try
            {
                return JsonConvert.DeserializeObject<List<cLiamNamingConvention>>(text) ?? new List<cLiamNamingConvention>();
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"Naming Conventions JSON ungültig: {ex.Message}");
            }
        }

        private void PopulateFields(cLiamProviderData data)
        {
            if (data == null)
                return;

            if (Enum.IsDefined(typeof(eLiamProviderTypes), data.ProviderType))
                ProviderTypeCombo.SelectedItem = data.ProviderType;

            DomainTextBox.Text = data.Domain ?? string.Empty;
            RootPathTextBox.Text = data.RootPath ?? string.Empty;
            MaxDepthTextBox.Text = data.MaxDepth.ToString();
            GroupFilterTextBox.Text = data.GroupFilter ?? string.Empty;
            GroupPathTextBox.Text = data.GroupPath ?? string.Empty;
            DataAreaFilterTextBox.Text = data.DataAreaFilter ?? string.Empty;
            DataAreaRegexTextBox.Text = data.DataAreaRegEx ?? string.Empty;
            GroupRegexTextBox.Text = data.GroupRegEx ?? string.Empty;
            TraverseGroupTextBox.Text = data.TraverseGroup ?? string.Empty;
            OwnerGroupGlobalTextBox.Text = data.OwnerGroupGlobal ?? string.Empty;
            OwnerGroupLocalTextBox.Text = data.OwnerGroupLocal ?? string.Empty;
            WriteGroupGlobalTextBox.Text = data.WriteGroupGlobal ?? string.Empty;
            WriteGroupLocalTextBox.Text = data.WriteGroupLocal ?? string.Empty;
            ReadGroupGlobalTextBox.Text = data.ReadGroupGlobal ?? string.Empty;
            ReadGroupLocalTextBox.Text = data.ReadGroupLocal ?? string.Empty;

            if (Enum.IsDefined(typeof(eLiamGroupStrategies), data.GroupStrategy))
                GroupStrategyCombo.SelectedItem = data.GroupStrategy;

            CredentialUserTextBox.Text = data.Credential?.Identification ?? string.Empty;
            CredentialDomainTextBox.Text = data.Credential?.Domain ?? string.Empty;
            CredentialPasswordBox.Password = string.Empty;

            AdditionalConfigTextBox.Text = FormatKeyValueLines(data.AdditionalConfiguration);
            CustomTagsTextBox.Text = FormatKeyValueLines(data.CustomTags);
            NamingConventionsTextBox.Text = data.NamingConventions != null && data.NamingConventions.Count > 0
                ? JsonConvert.SerializeObject(data.NamingConventions, Formatting.Indented)
                : string.Empty;

            UpdateProviderActionPanel();
            SaveSettings();
        }

        private string FormatKeyValueLines(Dictionary<string, string> source)
        {
            if (source == null || source.Count == 0)
                return string.Empty;

            var builder = new StringBuilder();
            foreach (var kvp in source)
            {
                builder.Append(kvp.Key);
                builder.Append('=');
                builder.AppendLine(kvp.Value);
            }
            return builder.ToString();
        }

        private int ParseInt(string value, int fallback)
        {
            if (int.TryParse(value, out var result))
                return result;
            return fallback;
        }

        private void ApplyLicense(string licenseRaw)
        {
            if (string.IsNullOrWhiteSpace(licenseRaw))
            {
                AppendLog("Keine Lizenz angegeben. Lizenzprüfung könnte fehlschlagen.", LogLevels.Warning);
                return;
            }

            try
            {
                if (cC4ITLicenseM42ESM.Instance == null)
                    _ = new cC4ITLicenseM42ESM(new Guid(cLIAMM42BaseActivity.LiamProductGuid));

                cC4ITLicenseM42ESM.Instance.LoadFromString(licenseRaw);
                AppendLog($"Lizenz geladen. Gültig: {cC4ITLicenseM42ESM.Instance.IsValid}", cC4ITLicenseM42ESM.Instance.IsValid ? LogLevels.Info : LogLevels.Warning);
            }
            catch (Exception ex)
            {
                AppendLog($"Lizenz konnte nicht geladen werden: {ex.Message}", LogLevels.Error);
                throw;
            }
        }

        private void ApplyMatrix42Environment(string serverName, bool useHttps)
        {
            var trimmed = serverName?.Trim();
            if (string.IsNullOrEmpty(trimmed))
            {
                AppendLog("Kein Portal-Server angegeben. Lizenz muss ggf. \"*\" enthalten.", LogLevels.Warning);
                return;
            }

            try
            {
                var instance = cMatrix42ServerInfo.DefaultInstance;
                if (instance == null)
                {
                    var type = typeof(cMatrix42ServerInfo);
                    instance = (cMatrix42ServerInfo)Activator.CreateInstance(type, nonPublic: true);
                    SetProperty(type, instance, "InstallationPath", string.Empty);
                }

                var lowered = trimmed.ToLowerInvariant();
                SetProperty(instance.GetType(), instance, "ServerName", lowered);
                SetProperty(instance.GetType(), instance, "IsHttps", useHttps);

                var defaultProp = typeof(cMatrix42ServerInfo).GetProperty("DefaultInstance", BindingFlags.Static | BindingFlags.Public);
                var setter = defaultProp?.GetSetMethod(true);
                setter?.Invoke(null, new object[] { instance });

                AppendLog($"Matrix42 ServerInfo gesetzt auf '{lowered}' (HTTPS={(useHttps ? "ja" : "nein")}).");
            }
            catch (Exception ex)
            {
                AppendLog($"Matrix42 ServerInfo konnte nicht gesetzt werden: {ex.Message}", LogLevels.Warning);
            }
        }

        private void SetProperty(Type type, object instance, string propertyName, object value)
        {
            var prop = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var setter = prop?.GetSetMethod(true);
            setter?.Invoke(instance, new[] { value });
        }

        private class ToolSettings
        {
            public int ProviderType { get; set; } = (int)eLiamProviderTypes.MsTeams;
            public int GroupStrategy { get; set; } = (int)eLiamGroupStrategies.Ntfs_AGDLP;
            public string Domain { get; set; } = string.Empty;
            public string RootPath { get; set; } = string.Empty;
            public string MaxDepth { get; set; } = "1";
            public string GroupFilter { get; set; } = string.Empty;
            public string GroupPath { get; set; } = string.Empty;
            public string DataAreaFilter { get; set; } = string.Empty;
            public string DataAreaRegex { get; set; } = string.Empty;
            public string GroupRegex { get; set; } = string.Empty;
            public string TraverseGroup { get; set; } = string.Empty;
            public string OwnerGroupGlobal { get; set; } = string.Empty;
            public string OwnerGroupLocal { get; set; } = string.Empty;
            public string WriteGroupGlobal { get; set; } = string.Empty;
            public string WriteGroupLocal { get; set; } = string.Empty;
            public string ReadGroupGlobal { get; set; } = string.Empty;
            public string ReadGroupLocal { get; set; } = string.Empty;
            public string CredentialUser { get; set; } = string.Empty;
            public string CredentialDomain { get; set; } = string.Empty;
            public string MaskToken { get; set; } = "***";
            public string AdditionalConfiguration { get; set; } = string.Empty;
            public string CustomTags { get; set; } = string.Empty;
            public string NamingConventions { get; set; } = string.Empty;
            public string RawJson { get; set; } = string.Empty;
            public string ProviderConfigClassId { get; set; } = string.Empty;
            public string ProviderConfigObjectId { get; set; } = string.Empty;
            public string ServerName { get; set; } = string.Empty;
            public bool UseHttps { get; set; } = false;
            public string License { get; set; } = string.Empty;
            public bool EnableWhatIf { get; set; } = true;
            public string NtfsCreateFolderPath { get; set; } = string.Empty;
            public string NtfsCreateParentPath { get; set; } = string.Empty;
            public string NtfsCreateOwnerSids { get; set; } = string.Empty;
            public string NtfsCreateReaderSids { get; set; } = string.Empty;
            public string NtfsCreateWriterSids { get; set; } = string.Empty;
            public string NtfsEnsureFolderPath { get; set; } = string.Empty;
            public string NtfsEnsureOwnerSids { get; set; } = string.Empty;
            public string NtfsEnsureReaderSids { get; set; } = string.Empty;
            public string NtfsEnsureWriterSids { get; set; } = string.Empty;
            public bool NtfsEnsureTraverse { get; set; } = false;
            public string AdServiceName { get; set; } = string.Empty;
            public string AdDescription { get; set; } = string.Empty;
            public int AdScope { get; set; } = (int)eLiamAccessRoleScopes.Universal;
            public int AdGroupType { get; set; } = (int)ADServiceGroupCreator.ADGroupType.Distribution;
            public string AdOwnerSids { get; set; } = string.Empty;
            public string AdMemberSids { get; set; } = string.Empty;
            public string MsTeamsSourceTeamId { get; set; } = string.Empty;
            public string MsTeamsNewName { get; set; } = string.Empty;
            public string MsTeamsDescription { get; set; } = string.Empty;
            public int MsTeamsVisibility { get; set; } = MsTeamsVisibilityPrivate;
            public bool MsTeamsCloneApps { get; set; } = false;
            public bool MsTeamsCloneTabs { get; set; } = false;
            public bool MsTeamsCloneSettings { get; set; } = true;
            public bool MsTeamsCloneChannels { get; set; } = true;
            public bool MsTeamsCloneMembers { get; set; } = false;
            public string MsTeamsAdditionalMembers { get; set; } = string.Empty;
            public string MsTeamsAdditionalOwners { get; set; } = string.Empty;
            public string ExchangeMailboxName { get; set; } = string.Empty;
            public string ExchangeMailboxAlias { get; set; } = string.Empty;
            public string ExchangeMailboxDisplayName { get; set; } = string.Empty;
            public string ExchangeMailboxPrimarySmtp { get; set; } = string.Empty;
            public string ExchangeDistributionName { get; set; } = string.Empty;
            public string ExchangeDistributionAlias { get; set; } = string.Empty;
            public string ExchangeDistributionDisplayName { get; set; } = string.Empty;
            public string ExchangeDistributionPrimarySmtp { get; set; } = string.Empty;
        }

        private sealed class MsTeamsVisibilityOption
        {
            public MsTeamsVisibilityOption(int value, string label)
            {
                Value = value;
                Label = label;
            }

            public int Value { get; }

            public string Label { get; }
        }
    }
}
