import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, BehaviorSubject, of, throwError } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { environment } from '@environments/environment';

export interface Machine {
  id?: number;
  machine_id?: string;
  machine_model: string;
  machine_type: string;
  client_id: number;
  client_name?: string;
  branch_id?: string;
  branch_name: string;
  operation_status: string;
  connection_status: string;
  created_on?: string;
  password?: string;
  slots?: any[];
  last_maintenance_date?: string;
  next_maintenance_date?: string;
  firmware_version?: string;
}

export interface VendingStateResponse {
  vendingRows: any[];
  lastUpdated?: string;
}

@Injectable({
  providedIn: 'root'
})
export class MachineService {
  private apiUrl = `${environment.apiUrl}/machines`;
  private usersUrl = `${environment.apiUrl}/users`;

  // 🔹 Loading state
  private loadingSource = new BehaviorSubject<boolean>(false);
  loading$ = this.loadingSource.asObservable();

  // 🔹 Selected machine shared state
  private selectedMachineSource = new BehaviorSubject<Machine | null>(null);
  selectedMachine$ = this.selectedMachineSource.asObservable();

  constructor(private http: HttpClient) {}

  // =====================
  // 🔹 Shared state methods
  // =====================
  setSelectedMachine(machine: Machine): void {
    this.selectedMachineSource.next(machine);
  }

  clearSelectedMachine(): void {
    this.selectedMachineSource.next(null);
  }

  // =====================
  // 🔹 CRUD methods
  // =====================
  getMachines(): Observable<Machine[]> {
    this.loadingSource.next(true);
    return this.http.get<Machine[]>(this.apiUrl).pipe(
      tap((machines) => console.log('Fetched all machines:', machines)),
      catchError(this.handleError<Machine[]>('getMachines', [])),
      tap(() => this.loadingSource.next(false))
    );
  }

  getUsers(): Observable<any[]> {
    return this.http.get<any[]>(this.usersUrl).pipe(
      tap((users) => console.log('Fetched users:', users)),
      catchError(this.handleError<any[]>('getUsers', []))
    );
  }

  addMachine(machine: Machine): Observable<Machine> {
    this.loadingSource.next(true);
    return this.http.post<Machine>(this.apiUrl, machine).pipe(
      tap((newMachine) => console.log('Added new machine:', newMachine)),
      catchError((error) => {
        console.error('Error adding machine:', error);
        this.loadingSource.next(false);
        return throwError(() => error);
      }),
      tap(() => this.loadingSource.next(false))
    );
  }

  updateMachine(id: number, machine: Machine): Observable<Machine> {
  this.loadingSource.next(true);
  return this.http.put<Machine>(`${this.apiUrl}/${id}`, machine).pipe(
    tap((updated) => console.log('Updated machine:', updated)),
    catchError(this.handleError<Machine>('updateMachine', {} as Machine)),
    tap(() => this.loadingSource.next(false))
  );
}

deleteMachine(id: number): Observable<any> {
  this.loadingSource.next(true);
  return this.http.delete(`${this.apiUrl}/${id}`).pipe(
    tap(() => console.log('Deleted machine with ID:', id)),
    catchError(this.handleError<any>('deleteMachine')),
    tap(() => this.loadingSource.next(false))
  );
}


  // =====================
  // 🔹 Advanced methods
  // =====================
  getMachineById(id: number): Observable<Machine> {
    return this.http.get<Machine>(`${this.apiUrl}/${id}`).pipe(
      tap((m) => console.log('Fetched machine by id:', m)),
      catchError(this.handleError<Machine>('getMachineById', {} as Machine))
    );
  }

  updateMachineStatus(
    id: number,
    status: { operation_status?: string; connection_status?: string }
  ): Observable<Machine> {
    return this.http.patch<Machine>(`${this.apiUrl}/${id}/status`, status).pipe(
      tap((m) => console.log('Updated status:', m)),
      catchError(this.handleError<Machine>('updateMachineStatus', {} as Machine))
    );
  }

  getMachineVendingState(machineId: string): Observable<VendingStateResponse> {
    return this.http
      .get<VendingStateResponse>(`${this.apiUrl}/${machineId}`)
      .pipe(
        tap((state) => console.log('Fetched vending state:', state)),
        catchError(
          this.handleError<VendingStateResponse>('getMachineVendingState', {
            vendingRows: []
          })
        )
      );
  }

  updateMachineVendingState(machineId: string, vendingState: any[]): Observable<any> {
    return this.http
      .put(`${this.apiUrl}/${machineId}/vending-state`, { vendingRows: vendingState })
      .pipe(
        tap((resp) => console.log('Updated vending state:', resp)),
        catchError(this.handleError<any>('updateMachineVendingState'))
      );
  }

  getMachineMaintenanceHistory(machineId: string): Observable<any[]> {
    return this.http
      .get<any[]>(`${this.apiUrl}/${machineId}/maintenance-history`)
      .pipe(
        tap((h) => console.log('Fetched maintenance history:', h)),
        catchError(this.handleError<any[]>('getMachineMaintenanceHistory', []))
      );
  }

  scheduleMaintenance(machineId: string, data: any): Observable<any> {
    return this.http.post(`${this.apiUrl}/${machineId}/maintenance`, data).pipe(
      tap((r) => console.log('Scheduled maintenance:', r)),
      catchError(this.handleError<any>('scheduleMaintenance'))
    );
  }

  // =====================
  // 🔹 Error handler
  // =====================
  private handleError<T>(operation = 'operation', result?: T) {
    return (error: HttpErrorResponse): Observable<T> => {
      console.error(`${operation} failed:`, error.message);
      return of(result as T);
    };
  }
}
