import {Injectable} from "@angular/core";
import {BehaviorSubject} from "rxjs";
import {HttpClient} from "@angular/common/http";

export interface StatusResponse {
  appNumber: number;
  status: string;
}

enum ApplicationStatus {
  AGREED = 'Согласована',
  ACCEPTED = 'Исполнена'
}

@Injectable({providedIn: 'root'})
export class StatusUpdateService {

  constructor(private httpClient: HttpClient) {
  }

  public statusMessage = new BehaviorSubject<any>(null);
  private pendingDeclarations = new Map<number, number>();
  private pollingInterval: any;
  private readonly MAX_ATTEMPTS = 12;

  public trackDeclaration(appNumber: number): void {
    if (!this.pendingDeclarations.has(appNumber)) {
      this.pendingDeclarations.set(appNumber, 0);
      this.startPolling();
    }
  }

  public publishStatus(appNumber: number, accepted: boolean) {
    this.statusMessage.next({
                              appNumber: appNumber,
                              status: accepted
                                      ? ApplicationStatus.ACCEPTED
                                      : ApplicationStatus.AGREED
                            });
  }

  private startPolling(): void {
    if (this.pendingDeclarations.size === 0 || this.pollingInterval) {
      return;
    }

    this.pollingInterval = setInterval(() => {
      this.checkPendingStatuses();
    }, 5000);
  }

  private stopPolling(): void {
    if (this.pollingInterval) {
      clearInterval(this.pollingInterval);
      this.pollingInterval = null;
    }
  }

  private checkPendingStatuses(): void {
    const appNumbers = Array.from(this.pendingDeclarations.keys());
    if (appNumbers.length === 0) {
      this.stopPolling();
      return;
    }

    this.httpClient.post<StatusResponse[]>('status/batch', appNumbers)
        .toPromise()
        .then(responses => {
          responses.forEach(response => {
            const attemptCount = (this.pendingDeclarations.get(response.appNumber) || 0) + 1;
            this.pendingDeclarations.set(response.appNumber, attemptCount);

            if (response.status !== 'SENT') {
              this.pendingDeclarations.delete(response.appNumber);
              this.publishStatus(response.appNumber, response.status === 'ACCEPTED');
            }
            else if (attemptCount >= this.MAX_ATTEMPTS) {
              this.pendingDeclarations.delete(response.appNumber);
              console.warn(`Max attempts exceeded for declaration ${response.appNumber}`);
            }
          });

          if (this.pendingDeclarations.size === 0) {
            this.stopPolling();
          }
        })
        .catch(err => {
          console.error('Failed to check statuses', err);
          appNumbers.forEach(appNumber => {
            const attemptCount = (this.pendingDeclarations.get(appNumber) || 0) + 1;
            this.pendingDeclarations.set(appNumber, attemptCount);

            if (attemptCount >= this.MAX_ATTEMPTS) {
              this.pendingDeclarations.delete(appNumber);
              console.warn(`Max attempts exceeded for declaration ${appNumber} due to errors`);
            }
          });
        });
  }
}