package de.assecutor.votianlt.pages.base.ui.view;

import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.HasElement;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.avatar.Avatar;
import com.vaadin.flow.component.avatar.AvatarVariant;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.menubar.MenuBar;
import com.vaadin.flow.component.menubar.MenuBarVariant;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.Scroller;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.treegrid.TreeGrid;
import com.vaadin.flow.data.provider.hierarchy.TreeData;
import com.vaadin.flow.data.provider.hierarchy.TreeDataProvider;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.flow.shared.Registration;
import de.assecutor.votianlt.model.User;
import de.assecutor.votianlt.model.Language;
import de.assecutor.votianlt.pages.base.ui.component.DialogStylingHelper;
import de.assecutor.votianlt.pages.service.AppUserService;
import de.assecutor.votianlt.pages.view.EditProfileView;
import de.assecutor.votianlt.security.SecurityService;
import de.assecutor.votianlt.service.MessageBadgeUpdateService;
import de.assecutor.votianlt.service.MessageService;
import lombok.extern.slf4j.Slf4j;

import static com.vaadin.flow.theme.lumo.LumoUtility.*;

import java.util.List;
import java.util.Locale;
import java.util.Objects;

@AnonymousAllowed
@Slf4j
@Layout("main")
public final class MainLayout extends AppLayout {

    private final SecurityService securityService;
    private final MessageService messageService;
    private final MessageBadgeUpdateService messageBadgeUpdateService;
    private final AppUserService appUserService;
    private Div headerRef;
    private Scroller navRef;
    private Component userMenuRef;
    private TreeGrid<MenuTreeItem> tree;
    private long unreadMessagesCount;
    private Registration badgeUpdateRegistration;
    private final Div viewContainer = new Div();

    public MainLayout(SecurityService securityService, MessageService messageService,
            MessageBadgeUpdateService messageBadgeUpdateService, AppUserService appUserService) {
        this.securityService = securityService;
        this.messageService = messageService;
        this.messageBadgeUpdateService = messageBadgeUpdateService;
        this.appUserService = appUserService;
        addClassName("app-shell");
        setPrimarySection(Section.DRAWER);

        getStyle().set("--vaadin-app-layout-drawer-width", "336px");

        // Always build the drawer; keep references and toggle visibility on attach and
        // after navigation
        headerRef = createHeader();

        // Scroller für Navigation mit maximaler Höhe
        Component sideNav = createSideNav();
        navRef = new Scroller(sideNav);
        navRef.addClassName("app-drawer-scroll");
        navRef.setScrollDirection(Scroller.ScrollDirection.VERTICAL);

        userMenuRef = createUserMenu();
        addToDrawer(headerRef, navRef, userMenuRef);

        viewContainer.addClassName("view-container");
        getElement().appendChild(viewContainer.getElement());

        updateDrawerVisibility();

        // Re-check on attach (new UI/session) and on every navigation cycle
        addAttachListener(e -> updateDrawerVisibility());
    }

    private void updateDrawerVisibility() {
        boolean loggedIn = securityService.isUserLoggedIn();
        if (headerRef != null)
            headerRef.setVisible(loggedIn);
        if (navRef != null)
            navRef.setVisible(loggedIn);
        if (userMenuRef != null)
            userMenuRef.setVisible(loggedIn);
        setDrawerOpened(loggedIn);
    }

    private Div createHeader() {
        var appLogo = VaadinIcon.CUBES.create();
        appLogo.addClassNames(TextColor.PRIMARY, IconSize.LARGE);
        appLogo.addClassName("app-drawer-logo-icon");

        var appName = new Span("VotianLT");
        appName.addClassNames(FontWeight.SEMIBOLD, FontSize.LARGE);
        appName.addClassName("app-drawer-title");

        var header = new Div(appLogo, appName);
        header.addClassNames(Display.FLEX, Padding.MEDIUM, Gap.MEDIUM, AlignItems.CENTER);
        header.addClassName("app-drawer-header");
        header.getStyle().set("cursor", "pointer");
        header.getElement().setProperty("title", "Zum Dashboard");
        header.addClickListener(event -> UI.getCurrent().navigate(resolveHomeRoute()));
        return header;
    }

    private String resolveHomeRoute() {
        return securityService.hasRole("ADMIN") ? "admin-dashboard" : "dashboard";
    }

    private Component createSideNav() {
        // Create tree data with hierarchical menu structure
        TreeData<MenuTreeItem> treeData = new TreeData<>();

        // Root nodes
        MenuTreeItem auftragserstellungItem = new MenuTreeItem(getTranslation("nav.job.create"), "add_job",
                VaadinIcon.PLUS_CIRCLE);
        MenuTreeItem nachrichtenItem = new MenuTreeItem(getTranslation("nav.messages"), "messages",
                VaadinIcon.ENVELOPE);
        MenuTreeItem verwaltungItem = new MenuTreeItem(getTranslation("nav.management"), null, VaadinIcon.COG);
        MenuTreeItem benutzerItem = new MenuTreeItem(getTranslation("nav.users"), null, VaadinIcon.USER);

        // Add root items
        treeData.addItem(null, auftragserstellungItem);
        treeData.addItem(null, nachrichtenItem);
        treeData.addItem(null, verwaltungItem);
        treeData.addItem(null, benutzerItem);

        // Add children to "Verwaltung"
        treeData.addItem(verwaltungItem,
                new MenuTreeItem(getTranslation("nav.jobs"), "jobs", VaadinIcon.CLIPBOARD_TEXT));
        treeData.addItem(verwaltungItem,
                new MenuTreeItem(getTranslation("nav.invoices"), "invoices", VaadinIcon.FILE_TEXT));
        treeData.addItem(verwaltungItem,
                new MenuTreeItem(getTranslation("nav.customers"), "customers", VaadinIcon.USERS));
        treeData.addItem(verwaltungItem,
                new MenuTreeItem(getTranslation("nav.appusers"), "app-user", VaadinIcon.USERS));
        treeData.addItem(verwaltungItem,
                new MenuTreeItem(getTranslation("nav.statistics"), "statistics", VaadinIcon.BAR_CHART));

        // Add children to "Benutzer"
        treeData.addItem(benutzerItem,
                new MenuTreeItem(getTranslation("nav.profile"), "edit-profile", VaadinIcon.USER));
        treeData.addItem(benutzerItem,
                new MenuTreeItem(getTranslation("nav.imprint"), "impressum", VaadinIcon.INFO_CIRCLE));

        // Create Tree
        tree = new TreeGrid<>();
        tree.setDataProvider(new TreeDataProvider<>(treeData));
        tree.addClassName("app-nav-tree");
        tree.addThemeVariants(GridVariant.LUMO_NO_BORDER, GridVariant.LUMO_NO_ROW_BORDERS);
        tree.setAllRowsVisible(true);
        tree.setWidthFull();

        // Custom item renderer to show icon and label with badge
        var navColumn = tree.addComponentHierarchyColumn(item -> {
            HorizontalLayout row = new HorizontalLayout();
            row.setAlignItems(FlexComponent.Alignment.CENTER);
            row.setSpacing(true);
            row.setPadding(false);
            row.setMargin(false);
            row.getStyle().set("max-width", "calc(100% - 4px)");
            row.addClassName("app-nav-row");
            if (treeData.getParent(item) == null) {
                row.addClassName("app-nav-row-root");
            }
            if (verwaltungItem.equals(treeData.getParent(item))) {
                row.addClassName("app-nav-row-management-child");
            }
            if (benutzerItem.equals(treeData.getParent(item))) {
                row.addClassName("app-nav-row-user-child");
            }

            // Icon
            if (item.icon() != null) {
                Icon icon = item.icon().create();
                icon.setSize("var(--lumo-icon-size-s)");
                icon.getStyle().set("min-width", "var(--lumo-icon-size-s)");
                icon.addClassName("app-nav-icon");
                row.add(icon);
            }

            // Label
            Span label = new Span(item.label());
            label.getStyle().set("font-size", "var(--lumo-font-size-s)");
            label.getStyle().set("white-space", "nowrap");
            label.addClassName("app-nav-label");
            row.add(label);
            row.setFlexGrow(1, label);

            // Badge for messages
            if ("messages".equals(item.path()) && unreadMessagesCount > 0) {
                Span badge = new Span(String.valueOf(unreadMessagesCount));
                badge.getElement().getThemeList().add("badge");
                badge.addClassName("app-nav-badge");
                row.add(badge);
            }

            // Expand/collapse indicator for parent nodes
            Icon chevron = VaadinIcon.ANGLE_RIGHT.create();
            chevron.setSize("var(--lumo-icon-size-s)");
            chevron.addClassName("nav-expand-icon");
            row.add(chevron);

            return row;
        });
        navColumn.setAutoWidth(false);
        navColumn.setFlexGrow(1);

        // Handle selection/navigation
        tree.addSelectionListener(event -> {
            event.getFirstSelectedItem().ifPresent(item -> {
                if (item.path() != null && !item.path().isEmpty()) {
                    UI.getCurrent().navigate(item.path());
                }
            });
        });

        // Expand management and user nodes by default
        tree.expand(verwaltungItem, benutzerItem);

        // Create container
        VerticalLayout navContainer = new VerticalLayout();
        navContainer.setPadding(false);
        navContainer.setSpacing(false);
        navContainer.setWidthFull();
        navContainer.addClassName("app-nav-container");
        navContainer.add(tree);

        return navContainer;
    }

    /**
     * Updates the messages badge with the current unread count
     */
    private void updateMessagesBadge() {
        if (tree == null) {
            return;
        }

        unreadMessagesCount = resolveUnreadMessageCount();
        tree.getDataProvider().refreshAll();
    }

    /**
     * Record representing a menu item in the tree
     */
    private record MenuTreeItem(String label, String path, VaadinIcon icon) {
        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;
            MenuTreeItem that = (MenuTreeItem) o;
            return Objects.equals(label, that.label) && Objects.equals(path, that.path);
        }

        @Override
        public int hashCode() {
            return Objects.hash(label, path);
        }
    }

    private long resolveUnreadMessageCount() {
        if (!securityService.isUserLoggedIn()) {
            return 0;
        }

        try {
            // Get all AppUsers for the current user
            List<de.assecutor.votianlt.model.AppUser> appUsers = appUserService.findByCurrentUser();

            if (appUsers == null || appUsers.isEmpty()) {
                return 0;
            }

            // Count unread messages for all AppUsers (receiver = AppUser ID)
            long unread = 0;
            for (de.assecutor.votianlt.model.AppUser appUser : appUsers) {
                if (appUser != null && appUser.getId() != null) {
                    String appUserId = appUser.getId().toHexString();
                    unread += messageService.getUnreadMessageCount(appUserId);
                }
            }

            return unread;
        } catch (RuntimeException e) {
            log.error("Error resolving unread message count: {}", e.getMessage(), e);
            return 0;
        }
    }

    private Component createUserMenu() {
        var userMenu = new MenuBar();
        userMenu.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE);
        userMenu.addClassName("app-user-menu");

        // Dynamisch aktualisierbare Komponenten
        var avatar = new Avatar();
        avatar.addThemeVariants(AvatarVariant.LUMO_XSMALL);
        avatar.addClassNames(Margin.Right.SMALL);
        avatar.setColorIndex(5);
        avatar.addClassName("app-user-avatar");

        var userNameSpan = new Span();
        userNameSpan.addClassName("app-user-name");

        var userMenuItem = userMenu.addItem(avatar);
        userMenuItem.add(userNameSpan);

        // Profil anzeigen mit Navigation
        userMenuItem.getSubMenu().addItem(getTranslation("nav.showprofile"),
                e -> UI.getCurrent().navigate(EditProfileView.class));
        userMenuItem.getSubMenu().addItem(getTranslation("nav.logout"), e -> openLogoutConfirmDialog());

        // Update-Funktion für Benutzername und Avatar
        Runnable updateUserInfo = () -> {
            String currentUser = securityService.getCurrentUsername();
            avatar.setName(currentUser);
            userNameSpan.setText(currentUser);
        };

        // Initial und bei Attach aktualisieren
        updateUserInfo.run();
        addAttachListener(e -> updateUserInfo.run());

        return userMenu;
    }

    private void openLogoutConfirmDialog() {
        var dialog = DialogStylingHelper.createConfirmationDialog(
                getTranslation("logout.confirm.title"),
                getTranslation("logout.confirm.message"),
                "460px",
                getTranslation("button.cancel"),
                getTranslation("nav.logout"),
                securityService::logout,
                com.vaadin.flow.component.button.ButtonVariant.LUMO_PRIMARY,
                com.vaadin.flow.component.button.ButtonVariant.LUMO_ERROR);
        dialog.open();
    }

    @Override
    protected void onAttach(AttachEvent attachEvent) {
        super.onAttach(attachEvent);
        UI ui = attachEvent.getUI();

        // Drawer-Layout anpassen nach kurzer Verzögerung
        ui.access(() -> {
            getElement().executeJs(
                    "setTimeout(() => {"
                            + "  const drawer = this.shadowRoot?.querySelector('[part=drawer]');"
                            + "  if (drawer) {"
                            + "    drawer.style.display = 'flex';"
                            + "    drawer.style.flexDirection = 'column';"
                            + "    drawer.style.height = '100vh';"
                            + "    const scroller = drawer.querySelector('vaadin-scroller');"
                            + "    if (scroller) {"
                            + "      scroller.style.flex = '1 1 auto';"
                            + "      scroller.style.minHeight = '0';"
                            + "    }"
                            + "  }"
                            + "}, 100);");
        });

        // Apply user's preferred language immediately after login
        applyUserLanguagePreference();

        // Update badge immediately when layout is attached
        updateMessagesBadge();

        // Register listener for badge updates
        badgeUpdateRegistration = messageBadgeUpdateService.register(() -> {
            ui.access(() -> {
                updateMessagesBadge();
            });
        });
    }

    /**
     * Applies the user's preferred language if it differs from the current UI
     * locale. The primary locale setup happens in {@code LocaleVaadinInitListener}
     * before the layout is constructed. This method handles edge cases such as
     * language changes within an active session.
     */
    private void applyUserLanguagePreference() {
        try {
            if (securityService.isUserLoggedIn()) {
                User currentUser = securityService.getCurrentDatabaseUser();
                if (currentUser != null && currentUser.getLanguage() != null) {
                    UI ui = UI.getCurrent();
                    if (ui != null) {
                        Locale targetLocale = getLocaleFromLanguage(currentUser.getLanguage());
                        if (!targetLocale.equals(ui.getLocale())) {
                            ui.setLocale(targetLocale);
                            log.info("Applied locale {} for user {}", targetLocale, currentUser.getEmail());
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("Error applying user language preference: {}", e.getMessage(), e);
        }
    }

    private Locale getLocaleFromLanguage(Language language) {
        return switch (language) {
        case DE -> Locale.GERMAN;
        case EN -> Locale.ENGLISH;
        case FR -> Locale.FRENCH;
        case ES -> Locale.of("es", "ES");
        default -> Locale.GERMAN;
        };
    }

    @Override
    public void showRouterLayoutContent(HasElement content) {
        viewContainer.getElement().removeAllChildren();
        if (content != null) {
            viewContainer.getElement().appendChild(content.getElement());
        }
    }

    @Override
    protected void onDetach(DetachEvent detachEvent) {
        if (badgeUpdateRegistration != null) {
            badgeUpdateRegistration.remove();
            badgeUpdateRegistration = null;
        }
        super.onDetach(detachEvent);
    }
}
