package dev.lions.user.manager.client.view;

import dev.lions.user.manager.client.api.UserRestClient;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.dto.user.UserSearchResultDTO;
import jakarta.annotation.PostConstruct;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.primefaces.model.FilterMeta;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortMeta;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

@Named
@ViewScoped
@Slf4j
public class UserView implements Serializable {

    @Inject
    @RestClient
    UserRestClient userRestClient;

    @ConfigProperty(name = "lions.user.manager.default.realm", defaultValue = "test-realm")
    String defaultRealm;

    @Getter
    @Setter
    private LazyDataModel<UserDTO> users;

    @Getter
    @Setter
    private UserDTO selectedUser;

    @Getter
    @Setter
    private String selectedRealm;

    @Getter
    @Setter
    private String searchTerm;

    @PostConstruct
    public void init() {
        this.selectedRealm = defaultRealm;
        this.selectedUser = new UserDTO(); // Initialize to avoid NPE in dialogs before selection

        users = new LazyDataModel<UserDTO>() {
            @Override
            public int count(Map<String, FilterMeta> filterBy) {
                // Simplified count logic reusing search API
                try {
                    return (int) userRestClient
                            .searchUsers(selectedRealm, searchTerm, null, null, null, null, null, 0, 1).getTotalCount()
                            .intValue();
                } catch (Exception e) {
                    log.error("Error counting users", e);
                    return 0;
                }
            }

            @Override
            public List<UserDTO> load(int first, int pageSize, Map<String, SortMeta> sortBy,
                    Map<String, FilterMeta> filterBy) {
                try {
                    int page = first / pageSize;
                    UserSearchResultDTO result = userRestClient.searchUsers(selectedRealm, searchTerm, null, null, null,
                            null, null, page, pageSize);
                    setRowCount(result.getTotalCount().intValue());
                    return result.getUsers();
                } catch (Exception e) {
                    log.error("Error loading users", e);
                    FacesContext.getCurrentInstance().addMessage(null,
                            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur de chargement", e.getMessage()));
                    return List.of();
                }
            }

            @Override
            public UserDTO getRowData(String rowKey) {
                // Not ideal for lazy model, but needed for selection sometimes if not using
                // rowDataWrapper
                // Assuming ID is rowKey
                try {
                    return userRestClient.getUserById(rowKey, selectedRealm);
                } catch (Exception e) {
                    return null;
                }
            }

            @Override
            public String getRowKey(UserDTO user) {
                return user.getId();
            }
        };
    }

    public void openNew() {
        this.selectedUser = new UserDTO();
        this.selectedUser.setEnabled(true);
    }

    public void saveUser() {
        try {
            if (this.selectedUser.getId() == null) {
                // Create
                // Password handling: assume temporary password is set in UI
                if (this.selectedUser.getTemporaryPassword() == null
                        || this.selectedUser.getTemporaryPassword().isBlank()) {
                    // Generate or require password logic here. For now, let's assume UI requires
                    // it.
                }
                userRestClient.createUser(selectedRealm, this.selectedUser);
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Succès", "Utilisateur créé"));
            } else {
                // Update
                userRestClient.updateUser(this.selectedUser.getId(), selectedRealm, this.selectedUser);
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage("Succès", "Utilisateur mis à jour"));
            }
            // PrimeFaces.current().executeScript("PF('manageUserDialog').hide()"); //
            // Handled in xhtml via oncomplete
        } catch (Exception e) {
            log.error("Error saving user", e);
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", e.getMessage()));
        }
    }

    public void deleteUser() {
        try {
            userRestClient.deleteUser(this.selectedUser.getId(), selectedRealm, false);
            this.selectedUser = null;
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage("Succès", "Utilisateur supprimé (soft delete)"));
        } catch (Exception e) {
            log.error("Error deleting user", e);
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", e.getMessage()));
        }
    }

    public void downloadCSV() {
        try {
            String csvContent = userRestClient.exportUsersToCSV(selectedRealm);

            FacesContext facesContext = FacesContext.getCurrentInstance();
            ExternalContext externalContext = facesContext.getExternalContext();

            externalContext.setResponseContentType("text/csv");
            externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"users_export.csv\"");

            OutputStream output = externalContext.getResponseOutputStream();
            output.write(csvContent.getBytes(StandardCharsets.UTF_8));

            facesContext.responseComplete();
        } catch (IOException e) {
            log.error("Error exporting CSV", e);
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur Export", e.getMessage()));
        }
    }
}
