import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of, forkJoin } from 'rxjs';
import { map, catchError, switchMap } from 'rxjs/operators';
import { Course, CourseType, CourseStatut } from '../interfaces/course';
import { normalizePage } from '@shared/paging/normalize-page';
import { PaginatedHttpService } from '@shared/paging/paginated-http.service';
import { ListParams, PagedResult } from '@shared/paging/paging';
import { environment } from 'src/environments/environment.development';
import { Reunion } from '../interfaces/reunion';
import { ReunionService } from './reunion';
import { NonPartantService } from './non-partant';

const USE_SERVER = true;
const API_BASE = '/api/v1/courses';
// Interface to match the API response structure for Course
interface CourseApiResponse {
  id: number;
  type: string;
  numero: number;
  nom: string;
  dateDepartCourse: string;
  dateDebutParis: string;
  dateFinParis: string;
  reunionId: number; // API returns reunionId
  reunionCourse: number;
  particularite?: string;
  partants: number;
  distance: number;
  condition?: string;
  estTerminee: boolean;
  estAnnulee: boolean;
  statut: CourseStatut;
  nombreChevauxInscrits: number;
  createdBy: string;
  validatedBy: string | null;
  createdAt: string | null;
  updatedAt: string | null;
  nonPartants: string[];
  adeadHeat: boolean;
}

@Injectable({ providedIn: 'root' })
export class CourseService {
  private apiUrl = environment.apiBaseUrl + API_BASE;

  constructor(
    private http: HttpClient,
    private paginatedHttp: PaginatedHttpService,
    private reunionService: ReunionService, // Inject ReunionService
    private nonPartantService: NonPartantService // Inject NonPartantService
  ) {}

  // Helper method to get ngrok bypass headers
  private getNgrokHeaders(): Record<string, string> {
    const isNgrok =
      environment.apiBaseUrl.includes('ngrok-free.app') ||
      environment.apiBaseUrl.includes('ngrok.io') ||
      environment.apiBaseUrl.includes('ngrok');
    return isNgrok ? { 'ngrok-skip-browser-warning': 'true' } : {};
  }

  list(
    params: ListParams,
    usePaginationEndpoint: boolean = false
  ): Observable<PagedResult<Course>> {
    if (USE_SERVER) {
      // If there's a search query, use the search endpoint
      if (params.search && params.search.trim()) {
        return this.search(params.search.trim()).pipe(
          map((courses) => {
            // Apply client-side sorting and pagination
            let filtered = [...courses];

            // Sort
            if (params.sortKey && params.sortDir) {
              const { sortKey, sortDir } = params;
              filtered.sort((a: any, b: any) => {
                const getValue = (obj: any, path: string): any =>
                  path.split('.').reduce((o, key) => o?.[key], obj);

                const va = getValue(a, sortKey);
                const vb = getValue(b, sortKey);
                const sa = va == null ? '' : String(va);
                const sb = vb == null ? '' : String(vb);
                const cmp = sa.localeCompare(sb, 'fr', { numeric: true });
                return sortDir === 'asc' ? cmp : -cmp;
              });
            }

            const total = filtered.length;
            const start = (params.page - 1) * params.perPage;
            const pageData = filtered.slice(start, start + params.perPage);

            const totalByType = filtered.reduce<Record<string, number>>((acc, c) => {
              const type = String(c.type);
              acc[type] = (acc[type] ?? 0) + 1;
              return acc;
            }, {});
            const totalRunning = filtered.filter(
              (c) => c.statut === CourseStatut.RUNNING || c.statut === 'RUNNING'
            ).length;
            const totalClosed = filtered.filter(
              (c) => c.statut === CourseStatut.CLOSED || c.statut === 'CLOSED'
            ).length;

            return normalizePage<Course>(
              {
                data: pageData,
                meta: {
                  total,
                  totalRunning,
                  totalClosed,
                  totalByType,
                },
              },
              params.page,
              params.perPage
            );
          }),
          catchError((err) => {
            console.error('Error searching courses:', err);
            return of(
              normalizePage<Course>(
                {
                  data: [],
                  meta: {
                    total: 0,
                    totalRunning: 0,
                    totalClosed: 0,
                    totalByType: {},
                  },
                },
                params.page,
                params.perPage
              )
            );
          })
        );
      }

      if (usePaginationEndpoint) {
        return this.paginatedHttp
          .fetch<CourseApiResponse>(this.apiUrl, params, {
            zeroBasedPageIndex: false,
          })
          .pipe(
            switchMap((pagedResult) => {
              // Handle empty data case
              if (!pagedResult.data || pagedResult.data.length === 0) {
                return of(
                  normalizePage<Course>(
                    {
                      data: [],
                      meta: {
                        total: pagedResult.meta?.total ?? 0,
                        totalRunning: 0,
                        totalClosed: 0,
                        totalByType: {},
                      },
                    },
                    params.page,
                    params.perPage
                  )
                );
              }

              // Extract unique reunionIds
              const uniqueReunionIds = [
                ...new Set(pagedResult.data.map((c) => String(c.reunionId))),
              ];

              // If no reunion IDs, we can't build valid Reunion objects – return empty page
              if (uniqueReunionIds.length === 0) {
                return of(
                  normalizePage<Course>(
                    {
                      data: [],
                      meta: {
                        total: pagedResult.meta?.total ?? 0,
                        totalRunning: 0,
                        totalClosed: 0,
                        totalByType: {},
                      },
                    },
                    params.page,
                    params.perPage
                  )
                );
              }

              // Fetch all reunions in parallel
              const reunionRequests = uniqueReunionIds.map((id) =>
                this.reunionService
                  .getById(id)
                  .pipe(catchError(() => of<Reunion | undefined>(undefined)))
              );

              return forkJoin(reunionRequests).pipe(
                map((reunions) => {
                  // Create a map of reunionId -> Reunion
                  const reunionMap = new Map<string, Reunion>();
                  uniqueReunionIds.forEach((id, index) => {
                    const reunion = reunions[index];
                    if (reunion) {
                      reunionMap.set(id, reunion);
                    }
                  });

                  // Transform API data to Course objects
                  const transformedData: Course[] = pagedResult.data
                    .map((apiCourse) => {
                      const reunion = reunionMap.get(String(apiCourse.reunionId));
                      if (!reunion) {
                        // If we couldn't resolve the reunion, drop this course to keep typing sound
                        return null;
                      }
                      return {
                        id: String(apiCourse.id),
                        type: apiCourse.type,
                        numero: apiCourse.numero,
                        nom: apiCourse.nom,
                        dateDepartCourse: apiCourse.dateDepartCourse,
                        dateDebutParis: apiCourse.dateDebutParis,
                        dateFinParis: apiCourse.dateFinParis,
                        reunion,
                        reunionCourse: apiCourse.reunionCourse,
                        particularite: apiCourse.particularite,
                        partants: apiCourse.partants,
                        distance: apiCourse.distance,
                        condition: apiCourse.condition,
                        statut: apiCourse.statut as CourseStatut,
                        nonPartants: apiCourse.nonPartants || [],
                        estTerminee: apiCourse.estTerminee,
                        estAnnulee: apiCourse.estAnnulee,
                        nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                        adeadHeat: apiCourse.adeadHeat,
                        createdBy: apiCourse.createdBy,
                        validatedBy: apiCourse.validatedBy,
                        createdAt: apiCourse.createdAt || new Date().toISOString(),
                        updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                      } as Course;
                    })
                    .filter((c): c is Course => c !== null);

                  // Calculate meta stats
                  const totalByType = transformedData.reduce<Record<string, number>>((acc, c) => {
                    const type = String(c.type);
                    acc[type] = (acc[type] ?? 0) + 1;
                    return acc;
                  }, {});
                  const totalRunning = transformedData.filter(
                    (c) => c.statut === CourseStatut.RUNNING || c.statut === 'RUNNING'
                  ).length;
                  const totalClosed = transformedData.filter(
                    (c) => c.statut === CourseStatut.CLOSED || c.statut === 'CLOSED'
                  ).length;

                  return normalizePage<Course>(
                    {
                      data: transformedData,
                      meta: {
                        total: pagedResult.meta?.total ?? transformedData.length,
                        totalRunning,
                        totalClosed,
                        totalByType,
                      },
                    },
                    params.page,
                    params.perPage
                  );
                })
              );
            }),
            catchError((err) => {
              console.error('Error fetching courses:', err);
              return of(
                normalizePage<Course>(
                  {
                    data: [],
                    meta: {
                      total: 0,
                      totalRunning: 0,
                      totalClosed: 0,
                      totalByType: {},
                    },
                  },
                  params.page,
                  params.perPage
                )
              );
            })
          );
      } else {
        // Fetch all data and apply client-side pagination
        return this.http
          .get<CourseApiResponse[]>(this.apiUrl, { headers: this.getNgrokHeaders() })
          .pipe(
            switchMap((apiData) => {
              // Handle empty data case
              if (!apiData || apiData.length === 0) {
                return of(
                  normalizePage<Course>(
                    {
                      data: [],
                      meta: {
                        total: 0,
                        totalRunning: 0,
                        totalClosed: 0,
                        totalByType: {},
                      },
                    },
                    params.page,
                    params.perPage
                  )
                );
              }

              // Extract unique reunionIds
              const uniqueReunionIds = [...new Set(apiData.map((c) => String(c.reunionId)))];

              // Handle case where there are no unique IDs (shouldn't happen, but be safe)
              if (uniqueReunionIds.length === 0) {
                return of(
                  normalizePage<Course>(
                    {
                      data: [],
                      meta: {
                        total: 0,
                        totalRunning: 0,
                        totalClosed: 0,
                        totalByType: {},
                      },
                    },
                    params.page,
                    params.perPage
                  )
                );
              }

              // Fetch all reunions in parallel
              const reunionRequests = uniqueReunionIds.map((id) =>
                this.reunionService
                  .getById(id)
                  .pipe(catchError(() => of<Reunion | undefined>(undefined)))
              );

              return forkJoin(reunionRequests).pipe(
                map((reunions) => {
                  // Create a map of reunionId -> Reunion
                  const reunionMap = new Map<string, Reunion>();
                  uniqueReunionIds.forEach((id, index) => {
                    const reunion = reunions[index];
                    if (reunion) {
                      reunionMap.set(id, reunion);
                    }
                  });

                  // Transform API data to Course objects
                  const transformedData: Course[] = apiData
                    .map((apiCourse) => {
                      const reunion = reunionMap.get(String(apiCourse.reunionId));
                      if (!reunion) {
                        return null;
                      }
                      return {
                        id: String(apiCourse.id),
                        type: apiCourse.type,
                        numero: apiCourse.numero,
                        nom: apiCourse.nom,
                        dateDepartCourse: apiCourse.dateDepartCourse,
                        dateDebutParis: apiCourse.dateDebutParis,
                        dateFinParis: apiCourse.dateFinParis,
                        reunion,
                        reunionCourse: apiCourse.reunionCourse,
                        particularite: apiCourse.particularite,
                        partants: apiCourse.partants,
                        distance: apiCourse.distance,
                        condition: apiCourse.condition,
                        statut: apiCourse.statut as CourseStatut,
                        nonPartants: apiCourse.nonPartants || [],
                        estTerminee: apiCourse.estTerminee,
                        estAnnulee: apiCourse.estAnnulee,
                        nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                        adeadHeat: apiCourse.adeadHeat,
                        createdBy: apiCourse.createdBy,
                        validatedBy: apiCourse.validatedBy,
                        createdAt: apiCourse.createdAt || new Date().toISOString(),
                        updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                      } as Course;
                    })
                    .filter((c): c is Course => c !== null);

                  // Apply client-side filtering, sorting, and pagination
                  let filtered = this.applyClientFilters(transformedData, params);
                  const total = filtered.length;
                  const start = (params.page - 1) * params.perPage;
                  const pageData = filtered.slice(start, start + params.perPage);

                  const totalByType = filtered.reduce<Record<string, number>>((acc, c) => {
                    const type = String(c.type);
                    acc[type] = (acc[type] ?? 0) + 1;
                    return acc;
                  }, {});
                  const totalRunning = filtered.filter(
                    (c) => c.statut === CourseStatut.RUNNING || c.statut === 'RUNNING'
                  ).length;
                  const totalClosed = filtered.filter(
                    (c) => c.statut === CourseStatut.CLOSED || c.statut === 'CLOSED'
                  ).length;

                  return normalizePage<Course>(
                    {
                      data: pageData,
                      meta: {
                        total,
                        totalRunning,
                        totalClosed,
                        totalByType,
                      },
                    },
                    params.page,
                    params.perPage
                  );
                })
              );
            }),
            catchError((err) => {
              console.error('Error fetching courses:', err);
              return of(
                normalizePage<Course>(
                  {
                    data: [],
                    meta: {
                      total: 0,
                      totalRunning: 0,
                      totalClosed: 0,
                      totalByType: {},
                    },
                  },
                  params.page,
                  params.perPage
                )
              );
            })
          );
      }
    }

    // If USE_SERVER is false, return empty result
    return of(
      normalizePage<Course>(
        {
          data: [],
          meta: {
            total: 0,
            totalRunning: 0,
            totalClosed: 0,
            totalByType: {},
          },
        },
        params.page,
        params.perPage
      )
    );
  }

  private applyClientFilters(data: Course[], params: ListParams): Course[] {
    let filtered = [...data];

    // Search filter
    const q = (params.search ?? '').toLowerCase();
    if (q) {
      filtered = filtered.filter((c) => {
        const reunionName = c.reunion?.nom?.toLowerCase?.() ?? '';
        const hippodromeName = c.reunion?.hippodrome?.nom?.toLowerCase?.() ?? '';
        return (
          c.nom.toLowerCase().includes(q) ||
          c.type.toLowerCase().includes(q) ||
          reunionName.includes(q) ||
          hippodromeName.includes(q)
        );
      });
    }

    // Sort
    if (params.sortKey && params.sortDir) {
      const { sortKey, sortDir } = params;
      filtered.sort((a: any, b: any) => {
        const getValue = (obj: any, path: string): any =>
          path.split('.').reduce((o, key) => o?.[key], obj);

        const va = getValue(a, sortKey);
        const vb = getValue(b, sortKey);
        const sa = va == null ? '' : String(va);
        const sb = vb == null ? '' : String(vb);
        const cmp = sa.localeCompare(sb, 'fr', { numeric: true });
        return sortDir === 'asc' ? cmp : -cmp;
      });
    }

    return filtered;
  }

  getById(id: string): Observable<Course | undefined> {
    if (USE_SERVER) {
      return this.http
        .get<CourseApiResponse>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
        .pipe(
          switchMap((apiCourse) => {
            // Fetch the reunion (non-partants are already included in the API response)
            return this.reunionService.getById(String(apiCourse.reunionId)).pipe(
              map((reunion) => {
                if (!reunion) {
                  return undefined;
                }
                return {
                  id: String(apiCourse.id),
                  type: apiCourse.type,
                  numero: apiCourse.numero,
                  nom: apiCourse.nom,
                  dateDepartCourse: apiCourse.dateDepartCourse,
                  dateDebutParis: apiCourse.dateDebutParis,
                  dateFinParis: apiCourse.dateFinParis,
                  reunion,
                  reunionCourse: apiCourse.reunionCourse,
                  particularite: apiCourse.particularite,
                  partants: apiCourse.partants,
                  distance: apiCourse.distance,
                  condition: apiCourse.condition,
                  statut: apiCourse.statut as CourseStatut,
                  nonPartants: apiCourse.nonPartants || [],
                  estTerminee: apiCourse.estTerminee,
                  estAnnulee: apiCourse.estAnnulee,
                  nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                  adeadHeat: apiCourse.adeadHeat,
                  createdBy: apiCourse.createdBy,
                  validatedBy: apiCourse.validatedBy,
                  createdAt: apiCourse.createdAt || new Date().toISOString(),
                  updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                };
              })
            );
          }),
          catchError((err) => {
            console.error(`Error fetching course ${id}:`, err);
            return of(undefined);
          })
        );
    }
    return of(undefined);
  }

  getByReunionId(reunionId: string): Observable<Course[]> {
    if (USE_SERVER) {
      return this.http
        .get<CourseApiResponse[]>(`${this.apiUrl}/reunion/${reunionId}`, {
          headers: this.getNgrokHeaders(),
        })
        .pipe(
          switchMap((apiData) => {
            // Fetch the reunion once
            return this.reunionService.getById(reunionId).pipe(
              map((reunion) => {
                if (!reunion) {
                  return [];
                }
                // Transform all courses with the same reunion
                return apiData.map((apiCourse) => ({
                  id: String(apiCourse.id),
                  type: apiCourse.type,
                  numero: apiCourse.numero,
                  nom: apiCourse.nom,
                  dateDepartCourse: apiCourse.dateDepartCourse,
                  dateDebutParis: apiCourse.dateDebutParis,
                  dateFinParis: apiCourse.dateFinParis,
                  reunion,
                  reunionCourse: apiCourse.reunionCourse,
                  particularite: apiCourse.particularite,
                  partants: apiCourse.partants,
                  distance: apiCourse.distance,
                  condition: apiCourse.condition,
                  statut: apiCourse.statut as CourseStatut,
                  nonPartants: apiCourse.nonPartants || [],
                  estTerminee: apiCourse.estTerminee,
                  estAnnulee: apiCourse.estAnnulee,
                  nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                  adeadHeat: apiCourse.adeadHeat,
                  createdBy: apiCourse.createdBy,
                  validatedBy: apiCourse.validatedBy,
                  createdAt: apiCourse.createdAt || new Date().toISOString(),
                  updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                }));
              })
            );
          }),
          catchError((err) => {
            console.error(`Error fetching courses for reunion ${reunionId}:`, err);
            return of([]);
          })
        );
    }
    return of([]);
  }

  search(query: string): Observable<Course[]> {
    if (USE_SERVER) {
      return this.http
        .get<CourseApiResponse[]>(`${this.apiUrl}/search`, {
          params: { q: query.trim() },
          headers: this.getNgrokHeaders(),
        })
        .pipe(
          switchMap((apiData) => {
            // Extract unique reunionIds
            const uniqueReunionIds = [...new Set(apiData.map((c) => String(c.reunionId)))];

            // Fetch all reunions in parallel
            const reunionRequests = uniqueReunionIds.map((id) =>
              this.reunionService
                .getById(id)
                .pipe(catchError(() => of<Reunion | undefined>(undefined)))
            );

            return forkJoin(reunionRequests).pipe(
              map((reunions) => {
                // Create a map of reunionId -> Reunion
                const reunionMap = new Map<string, Reunion>();
                uniqueReunionIds.forEach((id, index) => {
                  const reunion = reunions[index];
                  if (reunion) {
                    reunionMap.set(id, reunion);
                  }
                });

                // Transform API data to Course objects
                return apiData
                  .map((apiCourse) => {
                    const reunion = reunionMap.get(String(apiCourse.reunionId));
                    if (!reunion) {
                      return null;
                    }
                    return {
                      id: String(apiCourse.id),
                      type: apiCourse.type,
                      numero: apiCourse.numero,
                      nom: apiCourse.nom,
                      dateDepartCourse: apiCourse.dateDepartCourse,
                      dateDebutParis: apiCourse.dateDebutParis,
                      dateFinParis: apiCourse.dateFinParis,
                      reunion,
                      reunionCourse: apiCourse.reunionCourse,
                      particularite: apiCourse.particularite,
                      partants: apiCourse.partants,
                      distance: apiCourse.distance,
                      condition: apiCourse.condition,
                      statut: apiCourse.statut as CourseStatut,
                      nonPartants: apiCourse.nonPartants || [],
                      estTerminee: apiCourse.estTerminee,
                      estAnnulee: apiCourse.estAnnulee,
                      nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                      adeadHeat: apiCourse.adeadHeat,
                      createdBy: apiCourse.createdBy,
                      validatedBy: apiCourse.validatedBy,
                      createdAt: apiCourse.createdAt || new Date().toISOString(),
                      updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                    } as Course;
                  })
                  .filter((c): c is Course => c !== null);
              })
            );
          }),
          catchError((err) => {
            console.error(`Error searching courses with query ${query}:`, err);
            return of([]);
          })
        );
    }
    return of([]);
  }

  create(payload: Omit<Course, 'id' | 'nonPartants'>): Observable<Course> {
    if (USE_SERVER) {
      // Transform payload to API format (send reunionId instead of reunion object)
      const apiPayload: any = {
        type: payload.type,
        numero: payload.numero,
        nom: payload.nom,
        dateDepartCourse: payload.dateDepartCourse,
        dateDebutParis: payload.dateDebutParis,
        dateFinParis: payload.dateFinParis,
        reunionId: typeof payload.reunion === 'object' ? payload.reunion.id : payload.reunion,
        reunionCourse: payload.reunionCourse,
        particularite: payload.particularite,
        partants: payload.partants,
        distance: payload.distance,
        condition: payload.condition,
        statut: payload.statut,
        createdBy: payload.createdBy,
        validatedBy: payload.validatedBy,
      };

      return this.http
        .post<CourseApiResponse>(this.apiUrl, apiPayload, { headers: this.getNgrokHeaders() })
        .pipe(
          switchMap((apiCourse) => {
            // Fetch the reunion to build the full Course object
            return this.reunionService.getById(String(apiCourse.reunionId)).pipe(
              map((reunion) => {
                if (!reunion) {
                  throw new Error('Reunion not found');
                }
                const item: Course = {
                  id: String(apiCourse.id),
                  type: apiCourse.type,
                  numero: apiCourse.numero,
                  nom: apiCourse.nom,
                  dateDepartCourse: apiCourse.dateDepartCourse,
                  dateDebutParis: apiCourse.dateDebutParis,
                  dateFinParis: apiCourse.dateFinParis,
                  reunion,
                  reunionCourse: apiCourse.reunionCourse,
                  particularite: apiCourse.particularite,
                  partants: apiCourse.partants,
                  distance: apiCourse.distance,
                  condition: apiCourse.condition,
                  statut: apiCourse.statut as CourseStatut,
                  nonPartants: apiCourse.nonPartants || [],
                  estTerminee: apiCourse.estTerminee,
                  estAnnulee: apiCourse.estAnnulee,
                  nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                  adeadHeat: apiCourse.adeadHeat,
                  createdBy: apiCourse.createdBy,
                  validatedBy: apiCourse.validatedBy,
                  createdAt: apiCourse.createdAt || new Date().toISOString(),
                  updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                };
                return item;
              })
            );
          }),
          catchError((err) => {
            console.error('Error creating course:', err);
            throw err;
          })
        );
    }
    throw new Error('Server mode is required');
  }

  update(id: string, payload: Partial<Course>): Observable<Course | undefined> {
    if (USE_SERVER) {
      // Transform payload to API format (send reunionId instead of reunion object)
      const apiPayload: any = { ...payload };
      if (payload.reunion) {
        apiPayload.reunionId =
          typeof payload.reunion === 'object' ? payload.reunion.id : payload.reunion;
        delete apiPayload.reunion;
      }

      return this.http
        .put<CourseApiResponse>(`${this.apiUrl}/${id}`, apiPayload, {
          headers: this.getNgrokHeaders(),
        })
        .pipe(
          switchMap((apiCourse) => {
            // Fetch the reunion to build the full Course object
            return this.reunionService.getById(String(apiCourse.reunionId)).pipe(
              map((reunion) => {
                if (!reunion) {
                  throw new Error('Reunion not found');
                }
                return {
                  id: String(apiCourse.id),
                  type: apiCourse.type,
                  numero: apiCourse.numero,
                  nom: apiCourse.nom,
                  dateDepartCourse: apiCourse.dateDepartCourse,
                  dateDebutParis: apiCourse.dateDebutParis,
                  dateFinParis: apiCourse.dateFinParis,
                  reunion,
                  reunionCourse: apiCourse.reunionCourse,
                  particularite: apiCourse.particularite,
                  partants: apiCourse.partants,
                  distance: apiCourse.distance,
                  condition: apiCourse.condition,
                  statut: apiCourse.statut as CourseStatut,
                  nonPartants: apiCourse.nonPartants || [],
                  estTerminee: apiCourse.estTerminee,
                  estAnnulee: apiCourse.estAnnulee,
                  nombreChevauxInscrits: apiCourse.nombreChevauxInscrits,
                  adeadHeat: apiCourse.adeadHeat,
                  createdBy: apiCourse.createdBy,
                  validatedBy: apiCourse.validatedBy,
                  createdAt: apiCourse.createdAt || new Date().toISOString(),
                  updatedAt: apiCourse.updatedAt || new Date().toISOString(),
                };
              })
            );
          }),
          catchError((err) => {
            console.error(`Error updating course ${id}:`, err);
            return of(undefined);
          })
        );
    }
    throw new Error('Server mode is required');
  }

  updateStatut(id: string, statut: CourseStatut): Observable<Course | undefined> {
    if (USE_SERVER) {
      return this.http
        .patch<Course>(
          `${this.apiUrl}/${id}/statut`,
          { statut },
          { headers: this.getNgrokHeaders() }
        )
        .pipe(
          catchError((err) => {
            console.error(`Error updating course statut ${id}:`, err);
            return this.update(id, { statut });
          })
        );
    }
    return this.update(id, { statut });
  }

  delete(id: string): Observable<boolean> {
    if (USE_SERVER) {
      return this.http
        .delete<void>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
        .pipe(
          map(() => true),
          catchError((err) => {
            console.error(`Error deleting course ${id}:`, err);
            return of(false);
          })
        );
    }
    throw new Error('Server mode is required');
  }

  addNonPartant(courseId: string, npList: string[]) {
    console.warn('addNonPartant is deprecated. Use setNonPartants instead.');
    return this.setNonPartants(courseId, npList);
  }

  setNonPartants(courseId: string, npList: string[]): Observable<Course | undefined> {
    if (USE_SERVER) {
      // Use PUT endpoint to replace the entire list
      return this.nonPartantService.replaceNonPartants(courseId, npList).pipe(
        switchMap((updatedNonPartants) => {
          // Fetch the updated course to return it
          return this.getById(courseId).pipe(
            map((course) => {
              if (course) {
                return {
                  ...course,
                  nonPartants: updatedNonPartants,
                };
              }
              return undefined;
            })
          );
        }),
        catchError((err) => {
          console.error(`Error setting nonPartants for course ${courseId}:`, err);
          return of(undefined);
        })
      );
    }
    throw new Error('Server mode is required');
  }
}
