import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import {
  HubConnection, HubConnectionBuilder, HubConnectionState, LogLevel,
} from '@microsoft/signalr';
import { environment } from '../../../../environments/environment';
import { AttendanceCounts, AttendanceCategory } from '../models/attendance.model';

/**
 * Thin wrapper around the AttendanceHub SignalR connection. Exposes the latest
 * authoritative counts as an observable and a fire-and-forget increment() that
 * sends a batched delta to the server. The server broadcasts the new totals
 * back to every connected client.
 */
@Injectable({ providedIn: 'root' })
export class AttendanceSignalrService {
  // Hub lives at the host root; environment.apiUrl is e.g. http://localhost:42019/api
  private readonly hubUrl = environment.apiUrl.replace(/\/api\/?$/, '') + '/hubs/attendance';

  private connection?: HubConnection;
  private readonly counts$$ = new BehaviorSubject<AttendanceCounts | null>(null);

  /** Latest authoritative counts pushed by the server (null until first message). */
  get counts$(): Observable<AttendanceCounts | null> {
    return this.counts$$.asObservable();
  }

  async start(): Promise<void> {
    if (this.connection) {
      return;
    }

    this.connection = new HubConnectionBuilder()
      .withUrl(this.hubUrl)
      .withAutomaticReconnect()
      .configureLogging(LogLevel.Warning)
      .build();

    this.connection.on('ReceiveCounts', (counts: AttendanceCounts) => {
      this.counts$$.next(counts);
    });

    await this.connection.start();
  }

  async stop(): Promise<void> {
    if (this.connection) {
      await this.connection.stop();
      this.connection = undefined;
    }
  }

  /** Send a batched delta (may be negative) for one age group. */
  async increment(category: AttendanceCategory, delta: number): Promise<void> {
    if (delta === 0 || this.connection?.state !== HubConnectionState.Connected) {
      return;
    }
    await this.connection.invoke('Increment', category, delta);
  }

  /** Overwrite one age group with an absolute value (clamped at zero server-side). */
  async setCount(category: AttendanceCategory, value: number): Promise<void> {
    if (this.connection?.state !== HubConnectionState.Connected) {
      throw new Error('Not connected to the attendance hub.');
    }
    await this.connection.invoke('SetCount', category, value);
  }
}
