import { inject, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, Observable, of, tap } from 'rxjs';
import { Student } from '../models/student';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable({
  providedIn: 'root',
})
export class StudentService {
  private http = inject(HttpClient);
  private studentsUrl = 'http://localhost:8084/students';

  /** GET students from the server */
  getStudents(): Observable<Student[]> {
    return this.http.get<Student[]>(this.studentsUrl).pipe(
      tap((list) => this.log(`fetched ${list.length} students`)),
      catchError(this.handleError<Student[]>('getStudents', []))
    );
  }

  /** PATCH: partial update of an existing student */
  patchStudent(id: number, changes: Partial<Student>): Observable<Student> {
    const url = `${this.studentsUrl}/${id}`;
    return this.http.patch<Student>(url, changes, httpOptions).pipe(
      tap(_ => this.log(`patched student id=${id}`)),
      catchError(this.handleError<Student>('patchStudent'))
    );
  }

  /** PUT: update the student on the server (Original method) */
  updateStudent(student: Student, id: number): Observable<Student> {
    return this.http.put<Student>(`${this.studentsUrl}/${id}`, student, httpOptions).pipe(
      tap((studentUpdated: Student) => this.log(`updated student id=${studentUpdated.id}`)),
      catchError(this.handleError<any>('updateStudent'))
    );
  }




  /** PUT (All): update the entire collection (New for Lab 3) */
  // Send the entire array to replace the server-side collection
  updateAllStudents(students: Student[]): Observable<Student[]> {
    return this.http.put<Student[]>(`${this.studentsUrl}/new`, students);
  }

  /** POST: add a new student to the server */
  addStudent(student: Student): Observable<Student> {
    return this.http.post<Student>(this.studentsUrl, student, httpOptions).pipe(
      tap((newStudent: Student) => this.log(`added student w/ id=${newStudent.id}`)),
      catchError(this.handleError<Student>('addStudent'))
    );
  }

  /** DELETE: remove a student by id */
  deleteStudent(student: Student | number): Observable<Student> {
    const id = typeof student === 'number' ? student : student.id;
    const url = `${this.studentsUrl}/${id}`;
    return this.http.delete<Student>(url, httpOptions).pipe(
      tap(_ => this.log(`deleted student id=${id}`)),
      catchError(this.handleError<Student>('deleteStudent'))
    );
  }



  /** DELETE: delete all students from the server */
  deleteStudents(): Observable<any> {
    return this.http.delete(this.studentsUrl, httpOptions).pipe(
      tap(_ => this.log('deleted all students')),
      catchError(this.handleError<any>('deleteStudents'))
    );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      // Log the error to the console for debugging
      console.error(`${operation} failed:`, error);
      return of(result as T);
    };
  }

  private log(message: string) {
    console.log(`StudentService: ${message}`);
  }
}
