import { Injectable, inject, signal } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, tap, catchError, throwError } from 'rxjs';

export interface Reserva {
  id: string;
  resourceId: string;
  resourceName: string;
  date: string;      // 'YYYY-MM-DD'
  startTime: string; // 'HH:mm'
  endTime: string;   // 'HH:mm'
  author: string;
  notes?: string;
  createdAt: string;
}

export interface CreateReservaDto {
  resourceId: string;
  resourceName: string;
  date: string;
  startTime: string;
  endTime: string;
  author: string;
  notes?: string;
}

@Injectable({ providedIn: 'root' })
export class ReservasService {
  private http = inject(HttpClient);
  private readonly apiUrl = '/api/reservas';

  // Estado reactivo con Signals (Angular 18)
  reservas = signal<Reserva[]>([]);
  isLoading = signal<boolean>(false);
  error = signal<string | null>(null);

  /**
   * Carga todas las reservas o filtra por fecha (YYYY-MM-DD).
   * Actualiza el signal `reservas` con el resultado.
   */
  loadReservas(date?: string): Observable<Reserva[]> {
    this.isLoading.set(true);
    this.error.set(null);

    let params = new HttpParams();
    if (date) params = params.set('date', date);

    return this.http.get<Reserva[]>(this.apiUrl, { params }).pipe(
      tap((data) => {
        this.reservas.set(data);
        this.isLoading.set(false);
      }),
      catchError((err): Observable<never> => {
        this.isLoading.set(false);
        this.error.set('No se pudo conectar con el servidor.');
        return throwError(() => err);
      })
    );
  }

  /**
   * Crea una nueva reserva en Supabase vía el backend.
   * El backend rechaza duplicados (mismo recurso + fecha + hora) con 409.
   */
  create(dto: CreateReservaDto): Observable<Reserva> {
    this.isLoading.set(true);
    this.error.set(null);

    return this.http.post<Reserva>(this.apiUrl, dto).pipe(
      tap((nueva) => {
        // Optimistic update: agrega al inicio del signal
        this.reservas.update((prev) => [nueva, ...prev]);
        this.isLoading.set(false);
      }),
      catchError((err): Observable<never> => {
        this.isLoading.set(false);
        if (err.status === 409) {
          this.error.set('Este espacio ya está reservado para ese horario.');
        } else {
          this.error.set('Error al guardar la reserva.');
        }
        return throwError(() => err);
      })
    );
  }

  /**
   * Elimina una reserva por ID.
   */
  delete(id: string): Observable<{ message: string }> {
    return this.http.delete<{ message: string }>(`${`${this.apiUrl}/${id}`}`).pipe(
      tap(() => {
        this.reservas.update((prev) => prev.filter((r) => r.id !== id));
      }),
      catchError((err): Observable<never> => {
        return throwError(() => err);
      })
    );
  }

  /**
   * Verifica si un slot está ocupado consultando el estado local del signal.
   */
  isOccupied(resourceName: string, date: string, startTime: string): boolean {
    return this.reservas().some(
      (r) =>
        r.resourceName === resourceName &&
        r.date === date &&
        r.startTime === startTime
    );
  }
}