package de.assecutor.votianlt.service;

import de.assecutor.votianlt.model.User;
import de.assecutor.votianlt.model.invoices.CustomerInvoice;
import de.assecutor.votianlt.security.InvoiceRoles;
import de.assecutor.votianlt.security.SecurityService;
import org.springframework.stereotype.Service;

import java.util.Set;

/**
 * Berechtigungs-Checks für Rechnungsaktionen gemäß R-40 bis R-42.
 *
 * Backwards-compat: ein Nutzer mit der bestehenden {@code USER}- oder {@code ADMIN}-Rolle,
 * der keine der spezialisierten Invoice-Rollen besitzt, hat weiterhin volle Berechtigung
 * — andernfalls würden alle bestehenden Installationen sofort handlungsunfähig.
 *
 * Sobald ein Nutzer mindestens eine {@code INVOICE_*}-Rolle hat, gelten die feingranularen
 * Regeln und nur die explizit zugewiesenen Aktionen sind erlaubt.
 */
@Service
public class InvoicePermissionService {

    private static final String ROLE_ADMIN = "ADMIN";

    private final SecurityService securityService;

    public InvoicePermissionService(SecurityService securityService) {
        this.securityService = securityService;
    }

    public boolean canCreateOrIssue(User user) {
        return hasAnyInvoiceRole(user, InvoiceRoles.CREATOR) || isUnscoped(user);
    }

    public boolean canMarkAsSent(User user) {
        return hasAnyInvoiceRole(user, InvoiceRoles.CREATOR, InvoiceRoles.REVIEWER, InvoiceRoles.APPROVER)
                || isUnscoped(user);
    }

    public boolean canCancel(User user) {
        return hasAnyInvoiceRole(user, InvoiceRoles.APPROVER) || isUnscoped(user);
    }

    public boolean canCorrect(User user) {
        return hasAnyInvoiceRole(user, InvoiceRoles.APPROVER, InvoiceRoles.REVIEWER) || isUnscoped(user);
    }

    public boolean canRecordPayment(User user) {
        return hasAnyInvoiceRole(user, InvoiceRoles.ACCOUNTANT, InvoiceRoles.APPROVER) || isUnscoped(user);
    }

    public void requireCreate(User user) {
        if (!canCreateOrIssue(user)) {
            throw new InvoiceLifecycleException(
                    "Sie haben keine Berechtigung, Rechnungen zu erstellen oder auszustellen.");
        }
    }

    public void requireSend(User user) {
        if (!canMarkAsSent(user)) {
            throw new InvoiceLifecycleException(
                    "Sie haben keine Berechtigung, Rechnungen als versendet zu markieren.");
        }
    }

    public void requireCancel(User user) {
        if (!canCancel(user)) {
            throw new InvoiceLifecycleException(
                    "Sie haben keine Berechtigung, Rechnungen zu stornieren.");
        }
    }

    public void requireCorrect(User user) {
        if (!canCorrect(user)) {
            throw new InvoiceLifecycleException(
                    "Sie haben keine Berechtigung, Berichtigungsbelege zu erstellen.");
        }
    }

    public void requirePayment(User user) {
        if (!canRecordPayment(user)) {
            throw new InvoiceLifecycleException("Sie haben keine Berechtigung, Zahlungen zu erfassen.");
        }
    }

    /**
     * Convenience: prüft, ob der Nutzer Eigentümer einer Rechnung ist (oder Admin).
     * Wird genutzt, um Cross-Tenant-Zugriffe zu verhindern.
     */
    public boolean isOwnerOrAdmin(User user, CustomerInvoice invoice) {
        if (user == null) {
            return false;
        }
        if (isAdmin(user)) {
            return true;
        }
        if (invoice == null || invoice.getUserId() == null || user.getId() == null) {
            return false;
        }
        return invoice.getUserId().equals(user.getId().toHexString());
    }

    private boolean hasAnyInvoiceRole(User user, String... roles) {
        if (user == null || user.getRoles() == null) {
            return false;
        }
        Set<String> userRoles = user.getRoles();
        if (userRoles.contains(ROLE_ADMIN)) {
            return true;
        }
        for (String role : roles) {
            if (userRoles.contains(role)) {
                return true;
            }
        }
        return false;
    }

    /**
     * {@code true}, wenn dem Nutzer keine spezialisierte Invoice-Rolle zugewiesen ist —
     * dann gilt das alte Pauschalrecht der USER-Rolle (Backwards-Compat).
     */
    private boolean isUnscoped(User user) {
        if (user == null || user.getRoles() == null) {
            return false;
        }
        Set<String> roles = user.getRoles();
        return roles.stream().noneMatch(r -> r.startsWith("INVOICE_"));
    }

    private boolean isAdmin(User user) {
        return user != null && user.getRoles() != null && user.getRoles().contains(ROLE_ADMIN);
    }

    /** Bequemer Lookup für die UI. */
    public User currentUser() {
        return securityService.getCurrentDatabaseUser();
    }
}
