package dev.lions.unionflow.client.view;

import dev.lions.unionflow.client.service.ErrorHandlerService;
import dev.lions.unionflow.client.service.FinanceApprovalService;
import dev.lions.unionflow.server.api.dto.finance_workflow.request.ApproveTransactionRequest;
import dev.lions.unionflow.server.api.dto.finance_workflow.request.CreateBudgetRequest;
import dev.lions.unionflow.server.api.dto.finance_workflow.request.RejectTransactionRequest;
import dev.lions.unionflow.server.api.dto.finance_workflow.response.BudgetResponse;
import dev.lions.unionflow.server.api.dto.finance_workflow.response.TransactionApprovalResponse;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Data;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;

@Named("approbationsFinanceBean")
@SessionScoped
@Data
public class ApprobationsFinanceBean implements Serializable {

    private static final Logger LOGGER = Logger.getLogger(ApprobationsFinanceBean.class.getName());

    @Inject
    @RestClient
    private FinanceApprovalService financeApprovalService;

    @Inject
    private ErrorHandlerService errorHandler;

    @Inject
    private UserSession userSession;

    private List<TransactionApprovalResponse> approbationsEnAttente = new ArrayList<>();
    private List<TransactionApprovalResponse> historiqueApprobations = new ArrayList<>();
    private TransactionApprovalResponse approbationSelectionnee;

    private List<BudgetResponse> budgets = new ArrayList<>();
    private BudgetResponse budgetSelectionne;
    private NouveauBudget nouveauBudget = new NouveauBudget();

    private String commentaireApprobation;
    private String raisonRejet;

    private Map<String, Object> statistiques;
    private long nombreEnAttente = 0;

    private String filtreStatut;
    private String dateDebut;
    private String dateFin;

    private int page = 0;
    private int taille = 20;

    @PostConstruct
    public void init() {
        chargerApprobationsEnAttente();
        chargerBudgets();
        chargerStatistiques();
    }

    private UUID getOrgId() {
        return userSession.getEntite() != null ? userSession.getEntite().getId() : null;
    }

    public void chargerApprobationsEnAttente() {
        try {
            UUID orgId = getOrgId();
            approbationsEnAttente = financeApprovalService.obtenirApprobationsEnAttente(orgId, page, taille);
            Map<String, Long> compteur = financeApprovalService.compterEnAttente(orgId);
            nombreEnAttente = compteur.getOrDefault("count", 0L);
        } catch (Exception e) {
            LOGGER.severe("Erreur chargement approbations: " + e.getMessage());
            approbationsEnAttente = new ArrayList<>();
        }
    }

    public void chargerHistorique() {
        try {
            UUID orgId = getOrgId();
            historiqueApprobations = financeApprovalService.obtenirHistorique(orgId, dateDebut, dateFin, filtreStatut, page, taille);
        } catch (Exception e) {
            LOGGER.severe("Erreur chargement historique: " + e.getMessage());
            historiqueApprobations = new ArrayList<>();
            ajouterMessageErreur("Impossible de charger l'historique.");
        }
    }

    public void chargerBudgets() {
        try {
            UUID orgId = getOrgId();
            budgets = financeApprovalService.listerBudgets(orgId, 0, 50);
        } catch (Exception e) {
            LOGGER.severe("Erreur chargement budgets: " + e.getMessage());
            budgets = new ArrayList<>();
        }
    }

    public void chargerStatistiques() {
        try {
            statistiques = financeApprovalService.obtenirStatistiques(
                getOrgId(), null, null);
        } catch (Exception e) {
            LOGGER.warning("Statistiques finance indisponibles: " + e.getMessage());
        }
    }

    public void selectionnerApprobation(TransactionApprovalResponse approbation) {
        this.approbationSelectionnee = approbation;
        this.commentaireApprobation = null;
        this.raisonRejet = null;
    }

    public void approuver() {
        if (approbationSelectionnee == null) return;
        try {
            ApproveTransactionRequest request = ApproveTransactionRequest.builder()
                .comment(commentaireApprobation)
                .build();
            financeApprovalService.approuver(approbationSelectionnee.getId(), request);
            approbationsEnAttente.removeIf(a -> a.getId().equals(approbationSelectionnee.getId()));
            nombreEnAttente = Math.max(0, nombreEnAttente - 1);
            approbationSelectionnee = null;
            ajouterMessageSucces("Transaction approuvée avec succès.");
        } catch (Exception e) {
            LOGGER.severe("Erreur approbation: " + e.getMessage());
            ajouterMessageErreur("Impossible d'approuver la transaction.");
        }
    }

    public void rejeter() {
        if (approbationSelectionnee == null || raisonRejet == null || raisonRejet.isBlank()) {
            ajouterMessageErreur("La raison du rejet est obligatoire.");
            return;
        }
        try {
            RejectTransactionRequest request = RejectTransactionRequest.builder()
                .reason(raisonRejet.trim())
                .build();
            financeApprovalService.rejeter(approbationSelectionnee.getId(), request);
            approbationsEnAttente.removeIf(a -> a.getId().equals(approbationSelectionnee.getId()));
            nombreEnAttente = Math.max(0, nombreEnAttente - 1);
            approbationSelectionnee = null;
            ajouterMessageSucces("Transaction rejetée.");
        } catch (Exception e) {
            LOGGER.severe("Erreur rejet: " + e.getMessage());
            ajouterMessageErreur("Impossible de rejeter la transaction.");
        }
    }

    public void creerBudget() {
        try {
            CreateBudgetRequest request = CreateBudgetRequest.builder()
                .name(nouveauBudget.nom)
                .description(nouveauBudget.description)
                .organizationId(getOrgId())
                .period(nouveauBudget.periode)
                .year(nouveauBudget.annee)
                .month(nouveauBudget.mois)
                .lines(new ArrayList<>())
                .build();
            BudgetResponse cree = financeApprovalService.creerBudget(request);
            budgets.add(0, cree);
            nouveauBudget = new NouveauBudget();
            ajouterMessageSucces("Budget créé avec succès.");
        } catch (Exception e) {
            LOGGER.severe("Erreur création budget: " + e.getMessage());
            ajouterMessageErreur("Impossible de créer le budget.");
        }
    }

    public void supprimerBudget(BudgetResponse budget) {
        try {
            financeApprovalService.supprimerBudget(budget.getId());
            budgets.remove(budget);
            ajouterMessageSucces("Budget supprimé.");
        } catch (Exception e) {
            ajouterMessageErreur("Impossible de supprimer le budget.");
        }
    }

    public void appliquerFiltres() {
        page = 0;
        chargerHistorique();
    }

    public void actualiser() {
        chargerApprobationsEnAttente();
        chargerBudgets();
        chargerStatistiques();
    }

    public String getStatusSeverity(String status) {
        if (status == null) return "info";
        return switch (status) {
            case "APPROVED", "VALIDATED", "ACTIVE" -> "success";
            case "REJECTED", "EXPIRED", "CANCELLED" -> "danger";
            case "PENDING", "DRAFT" -> "warning";
            default -> "info";
        };
    }

    private void ajouterMessageSucces(String detail) {
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", detail));
    }

    private void ajouterMessageErreur(String detail) {
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", detail));
    }

    @Data
    public static class NouveauBudget {
        private String nom;
        private String description;
        private String periode = "MONTHLY";
        private Integer annee = java.time.Year.now().getValue();
        private Integer mois;
    }
}
