package de.assecutor.votianlt.pages.view;

import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.assecutor.votianlt.dto.ClientMessageSummary;
import de.assecutor.votianlt.model.AppUser;
import de.assecutor.votianlt.model.Message;
import de.assecutor.votianlt.model.MessageContentType;
import de.assecutor.votianlt.model.MessageOrigin;
import de.assecutor.votianlt.pages.service.AppUserService;
import de.assecutor.votianlt.service.MessageService;
import jakarta.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j;

import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import com.vaadin.flow.shared.Registration;

@Route(value = "messages", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@PageTitle("Nachrichten")
@Menu(order = 1, icon = "vaadin:envelope", title = "Nachrichten")
@RolesAllowed("USER")
@Slf4j
public class MessagesView extends Main {

    private static final int POLL_INTERVAL_MS = 5000;

    private final MessageService messageService;
    private final AppUserService appUserService;
    
    private Grid<ClientMessageSummary> clientGrid;
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
    private final AtomicBoolean loading = new AtomicBoolean(false);
    private Registration pollRegistration;

    public MessagesView(MessageService messageService, AppUserService appUserService) {
        this.messageService = messageService;
        this.appUserService = appUserService;

        // Create main layout
        VerticalLayout layout = new VerticalLayout();
        layout.setPadding(true);
        layout.setSpacing(true);
        layout.setWidthFull();

        // Add title and action buttons
        HorizontalLayout headerLayout = createHeaderLayout();
        
        // Create client grid
        clientGrid = createClientGrid();
        
        // Add components to layout
        layout.add(headerLayout, clientGrid);

        // Add layout to main view
        add(layout);
        
        // Load client summaries
        loadClientSummaries();
    }

    private HorizontalLayout createHeaderLayout() {
        H2 title = new H2("Nachrichten");
        HorizontalLayout layout = new HorizontalLayout(title);
        layout.setWidthFull();
        layout.setAlignItems(com.vaadin.flow.component.orderedlayout.FlexComponent.Alignment.CENTER);
        return layout;
    }

    private Grid<ClientMessageSummary> createClientGrid() {
        Grid<ClientMessageSummary> grid = new Grid<>(ClientMessageSummary.class, false);
        grid.setWidthFull();
        grid.setHeight("600px");
        
        // Add columns
        grid.addColumn(new ComponentRenderer<>(summary -> {
            Span span = new Span(summary.getUnreadCount() > 0 ? "●" : "○");
            span.getStyle().set("font-size", "20px");
            if (summary.getUnreadCount() > 0) {
                span.getStyle().set("color", "var(--lumo-primary-color)");
            }
            return span;
        })).setHeader("Status").setWidth("80px").setFlexGrow(0);
        
        grid.addColumn(ClientMessageSummary::getClientName).setHeader("Client").setAutoWidth(true);
        grid.addColumn(ClientMessageSummary::getClientEmail).setHeader("E-Mail").setAutoWidth(true);
        
        grid.addColumn(new ComponentRenderer<>(summary -> {
            Span span = new Span(String.valueOf(summary.getTotalMessages()));
            return span;
        })).setHeader("Nachrichten").setWidth("120px").setFlexGrow(0);
        
        grid.addColumn(new ComponentRenderer<>(summary -> {
            if (summary.getUnreadCount() > 0) {
                Span span = new Span(String.valueOf(summary.getUnreadCount()));
                span.getStyle().set("color", "var(--lumo-primary-color)");
                span.getStyle().set("font-weight", "bold");
                return span;
            }
            return new Span("0");
        })).setHeader("Ungelesen").setWidth("100px").setFlexGrow(0);
        
        grid.addColumn(summary -> 
            summary.getLastMessageDate() != null ? summary.getLastMessageDate().format(DATE_FORMATTER) : "-"
        ).setHeader("Letzte Nachricht").setAutoWidth(true);
        
        grid.addColumn(new ComponentRenderer<>(summary -> {
            String preview = summary.getLastMessagePreview();
            if (preview != null && preview.length() > 50) {
                preview = preview.substring(0, 47) + "...";
            }
            return new Span(preview != null ? preview : "-");
        })).setHeader("Vorschau").setAutoWidth(true);
        
        // Add click listener to navigate to UserMessagesView
        grid.addItemClickListener(event -> {
            ClientMessageSummary summary = event.getItem();
            UI.getCurrent().navigate("user-messages/" + summary.getClientId());
        });
        
        return grid;
    }

    private void loadClientSummaries() {
        if (!loading.compareAndSet(false, true)) {
            return;
        }
        try {
            List<AppUser> appUsers = Optional.ofNullable(appUserService.findByCurrentUser()).orElseGet(ArrayList::new);
            Map<String, AppUser> appUserLookup = buildAppUserLookup(appUsers);

            List<Message> allMessages = messageService.getAllMessages();
            Map<String, List<Message>> groupedByParticipant = groupMessagesByParticipant(allMessages);
            List<ClientMessageSummary> summaries = buildSummaries(groupedByParticipant, appUserLookup, appUsers);
            clientGrid.setItems(summaries);

        } catch (Exception e) {
            log.error("Error loading client summaries: {}", e.getMessage(), e);
            Notification.show("Fehler beim Laden der Nachrichten", 3000, Notification.Position.MIDDLE)
                .addThemeVariants(NotificationVariant.LUMO_ERROR);
        } finally {
            loading.set(false);
        }
    }

    private Map<String, List<Message>> groupMessagesByParticipant(List<Message> messages) {
        Map<String, List<Message>> grouped = new LinkedHashMap<>();
        for (Message message : messages) {
            String participantKey = resolveParticipantKey(message);
            if (participantKey == null || participantKey.isBlank()) {
                continue;
            }
            grouped.computeIfAbsent(participantKey, key -> new ArrayList<>()).add(message);
        }
        return grouped;
    }

    private List<ClientMessageSummary> buildSummaries(Map<String, List<Message>> groupedMessages,
            Map<String, AppUser> appUserLookup, List<AppUser> appUsers) {
        Map<String, ClientMessageSummary> summaryMap = new LinkedHashMap<>();

        for (Map.Entry<String, List<Message>> entry : groupedMessages.entrySet()) {
            String participantKey = entry.getKey();
            AppUser participant = resolveAppUser(participantKey, appUserLookup);
            if (participant == null) {
                continue; // Only display app users of the current account holder
            }

            String participantId = participant.getIdAsString();
            if (participantId == null || participantId.isBlank()) {
                continue;
            }

            ClientMessageSummary summary = summaryMap.computeIfAbsent(participantId,
                    id -> createEmptySummary(participant));

            List<Message> conversation = entry.getValue();
            if (conversation == null || conversation.isEmpty()) {
                continue;
            }

            conversation.sort(Comparator.comparing(Message::getCreatedAt,
                    Comparator.nullsLast(LocalDateTime::compareTo)).reversed());

            Message latest = conversation.stream()
                    .filter(msg -> msg.getCreatedAt() != null)
                    .findFirst()
                    .orElse(conversation.get(0));

            LocalDateTime lastDate = latest.getCreatedAt();
            String preview = resolvePreview(latest);
            int totalMessages = conversation.size();
            int unreadCount = (int) conversation.stream()
                    .filter(msg -> msg.getOrigin() == MessageOrigin.CLIENT && !msg.isRead())
                    .count();

            summary.setTotalMessages(summary.getTotalMessages() + totalMessages);
            summary.setUnreadCount(summary.getUnreadCount() + unreadCount);

            LocalDateTime currentLast = summary.getLastMessageDate();
            if (lastDate != null && (currentLast == null || lastDate.isAfter(currentLast))) {
                summary.setLastMessageDate(lastDate);
                summary.setLastMessagePreview(preview);
            }
        }

        for (AppUser appUser : appUsers) {
            if (appUser == null) {
                continue;
            }
            String appUserId = appUser.getIdAsString();
            if (appUserId != null && !summaryMap.containsKey(appUserId)) {
                summaryMap.put(appUserId, createEmptySummary(appUser));
            }
        }

        List<ClientMessageSummary> summaries = new ArrayList<>(summaryMap.values());
        summaries.sort(Comparator.comparing(ClientMessageSummary::getLastMessageDate,
                Comparator.nullsLast(LocalDateTime::compareTo)).reversed());
        return summaries;
    }

    private String resolvePreview(Message message) {
        if (message == null) {
            return "(kein Inhalt)";
        }

        if (message.getContentType() == MessageContentType.IMAGE) {
            return "[Bildnachricht]";
        }

        return Optional.ofNullable(message.getContent())
                .filter(content -> !content.isBlank())
                .orElse("(kein Inhalt)");
    }

    private String resolveParticipantKey(Message message) {
        if (message == null) {
            return null;
        }
        // All messages now have receiver = AppUser ID (clientId)
        return message.getReceiver();
    }

    private AppUser resolveAppUser(String participantKey, Map<String, AppUser> appUserLookup) {
        if (participantKey == null || participantKey.isBlank()) {
            return null;
        }
        String trimmed = participantKey.trim();
        AppUser directMatch = appUserLookup.get(trimmed);
        if (directMatch != null) {
            return directMatch;
        }
        return appUserLookup.get(trimmed.toLowerCase());
    }

    private String buildClientName(AppUser participant) {
        if (participant == null) {
            return "-";
        }
        String vorname = Optional.ofNullable(participant.getVorname()).orElse("").trim();
        String nachname = Optional.ofNullable(participant.getNachname()).orElse("").trim();

        String fullName = (vorname + " " + nachname).trim();
        if (!fullName.isEmpty()) {
            return fullName;
        }
        return Optional.ofNullable(participant.getBezeichnung()).orElse(participant.getIdAsString());
    }

    private ClientMessageSummary createEmptySummary(AppUser appUser) {
        String clientId = Optional.ofNullable(appUser.getIdAsString()).orElse("-");
        String clientName = buildClientName(appUser);
        String clientEmail = Optional.ofNullable(appUser.getEmail()).orElse("-");
        return new ClientMessageSummary(clientId, clientName, clientEmail, 0, 0, null, "-");
    }

    private Map<String, AppUser> buildAppUserLookup(List<AppUser> appUsers) {
        Map<String, AppUser> lookup = new LinkedHashMap<>();
        for (AppUser appUser : appUsers) {
            if (appUser == null) {
                continue;
            }
            addLookupEntry(lookup, appUser.getIdAsString(), appUser);
            addLookupEntry(lookup, appUser.getEmail(), appUser);
            addLookupEntry(lookup, appUser.getAppCode(), appUser);
        }
        return lookup;
    }

    private void addLookupEntry(Map<String, AppUser> lookup, String key, AppUser appUser) {
        if (key == null) {
            return;
        }
        String trimmed = key.trim();
        if (trimmed.isEmpty()) {
            return;
        }
        lookup.putIfAbsent(trimmed, appUser);
        lookup.putIfAbsent(trimmed.toLowerCase(), appUser);
    }

    @Override
    protected void onAttach(AttachEvent attachEvent) {
        super.onAttach(attachEvent);
        UI ui = attachEvent.getUI();
        ui.setPollInterval(POLL_INTERVAL_MS);
        pollRegistration = ui.addPollListener(event -> loadClientSummaries());
        loadClientSummaries();
    }

    @Override
    protected void onDetach(DetachEvent detachEvent) {
        super.onDetach(detachEvent);
        if (pollRegistration != null) {
            pollRegistration.remove();
            pollRegistration = null;
        }
        detachEvent.getUI().setPollInterval(-1);
    }
}
