import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import {
  HubConnection, HubConnectionBuilder, HubConnectionState, LogLevel,
} from '@microsoft/signalr';
import { environment } from '../../../../environments/environment';
import { OfferingEntryLineAddedDto } from '../models/giving.model';

/**
 * Thin wrapper around the OfferingEntryHub connection. Clients join the group
 * for a session date and receive a "LineAdded" event whenever any phone appends
 * a line for that date, so every device (and the desktop Sunday Offering Entry
 * page) updates its Lines list live. Mirrors AttendanceSignalrService.
 */
@Injectable({ providedIn: 'root' })
export class OfferingEntrySignalrService {
  // Hub lives at the host root; environment.apiUrl is e.g. http://localhost:42019/api
  private readonly hubUrl = environment.apiUrl.replace(/\/api\/?$/, '') + '/hubs/offering-entry';

  private connection?: HubConnection;
  private readonly lineAdded$$ = new Subject<OfferingEntryLineAddedDto>();

  /** Emits each line appended for a joined date (from this or any other client). */
  get lineAdded$(): Observable<OfferingEntryLineAddedDto> {
    return this.lineAdded$$.asObservable();
  }

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

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

    this.connection.on('LineAdded', (dto: OfferingEntryLineAddedDto) => {
      this.lineAdded$$.next(dto);
    });

    await this.connection.start();
  }

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

  /** Subscribe to live updates for one session date (yyyy-MM-dd). */
  async joinDate(date: string): Promise<void> {
    if (this.connection?.state !== HubConnectionState.Connected) {
      return;
    }
    await this.connection.invoke('JoinDate', date);
  }

  async leaveDate(date: string): Promise<void> {
    if (this.connection?.state !== HubConnectionState.Connected) {
      return;
    }
    await this.connection.invoke('LeaveDate', date);
  }
}
