import { Injectable } from '@angular/core'; import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; import { Observable, Subject, tap } from 'rxjs'; import { environment } from '../../environments/environment'; export type NotificationTipo = 'AVencer' | 'Vencido' | 'RenovacaoAutomatica' | string; export type NotificationDto = { id: string; tipo: NotificationTipo; titulo: string; mensagem: string; data: string; referenciaData?: string | null; diasParaVencer?: number | null; lida: boolean; lidaEm?: string | null; vigenciaLineId?: string | null; cliente?: string | null; linha?: string | null; usuario?: string | null; conta?: string | null; planoContrato?: string | null; dtEfetivacaoServico?: string | null; dtTerminoFidelizacao?: string | null; }; export type NotificationsEvent = | { type: 'read'; ids: string[]; readAtIso: string } | { type: 'unread'; ids: string[] } | { type: 'readAll'; readAtIso: string } | { type: 'unreadAll' } | { type: 'reload' }; @Injectable({ providedIn: 'root' }) export class NotificationsService { private readonly baseApi: string; private readonly eventsSubject = new Subject(); readonly events$ = this.eventsSubject.asObservable(); constructor(private http: HttpClient) { const raw = (environment.apiUrl || '').replace(/\/+$/, ''); this.baseApi = raw.toLowerCase().endsWith('/api') ? raw : `${raw}/api`; } list(): Observable { return this.http.get(`${this.baseApi}/notifications`); } markAsRead(id: string): Observable { const readAtIso = new Date().toISOString(); return this.http.patch(`${this.baseApi}/notifications/${id}/read`, {}).pipe( tap(() => this.eventsSubject.next({ type: 'read', ids: [id], readAtIso })) ); } markAsUnread(id: string): Observable { return this.http.patch(`${this.baseApi}/notifications/${id}/unread`, {}).pipe( tap(() => this.eventsSubject.next({ type: 'unread', ids: [id] })) ); } markAllAsRead(filter?: string, notificationIds?: string[]): Observable { let params = new HttpParams(); if (filter) params = params.set('filter', filter); const body = notificationIds && notificationIds.length ? { notificationIds } : {}; const readAtIso = new Date().toISOString(); return this.http.patch(`${this.baseApi}/notifications/read-all`, body, { params }).pipe( tap(() => { if (notificationIds && notificationIds.length) { this.eventsSubject.next({ type: 'read', ids: notificationIds, readAtIso }); return; } // Se não sabemos o escopo (sem IDs), preferimos sinalizar que "todas" foram lidas. // Para casos futuros de filtros sem IDs, o consumer pode optar por recarregar. this.eventsSubject.next(filter ? { type: 'reload' } : { type: 'readAll', readAtIso }); }) ); } markAllAsUnread(filter?: string, notificationIds?: string[]): Observable { let params = new HttpParams(); if (filter) params = params.set('filter', filter); const body = notificationIds && notificationIds.length ? { notificationIds } : {}; return this.http.patch(`${this.baseApi}/notifications/unread-all`, body, { params }).pipe( tap(() => { if (notificationIds && notificationIds.length) { this.eventsSubject.next({ type: 'unread', ids: notificationIds }); return; } this.eventsSubject.next(filter ? { type: 'reload' } : { type: 'unreadAll' }); }) ); } export(filter?: string, notificationIds?: string[]): Observable> { let params = new HttpParams(); if (filter) params = params.set('filter', filter); if (notificationIds && notificationIds.length) { return this.http.post(`${this.baseApi}/notifications/export`, { notificationIds }, { params, observe: 'response', responseType: 'blob' }); } return this.http.get(`${this.baseApi}/notifications/export`, { params, observe: 'response', responseType: 'blob' }); } }