import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of, forkJoin } from 'rxjs';
import { PaginatedHttpService } from '@shared/paging/paginated-http.service';
import { ListParams, PagedResult } from '@shared/paging/paging';
import { map, catchError, switchMap } from 'rxjs/operators';
import { Resultat, ResultatApiResponse, CreateResultatPayload } from '../interfaces/resultat';
import { Course } from '../interfaces/course';
import { CourseService } from './course';
import { environment } from 'src/environments/environment.development';

const USE_SERVER = true;
const API_BASE = '/api/resultats';

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

  constructor(private http: HttpClient, private courseService: CourseService, private pager: PaginatedHttpService) {}

    // Fetch raw paginated resultats from the backend and normalize paging
    listRawPaged(params: ListParams): Observable<PagedResult<ResultatApiResponse>> {
      const url = this.apiUrl;
      // Delegate to shared paginated HTTP helper (Spring-style defaults)
      return this.pager.fetch<ResultatApiResponse>(url, params);
    }

  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' } : {};
  }

  // GET /api/v1/resultat/{id}
  getById(id: string): Observable<Resultat | undefined> {
    if (USE_SERVER) {
      return this.http
        .get<ResultatApiResponse>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
        .pipe(
          switchMap((apiResultat) => {
            // New API uses `courseId` explicitly
            const courseId = String((apiResultat as any).courseId ?? '');

            return this.courseService.getById(courseId).pipe(
              map((course) => {
                if (!course) {
                  return undefined;
                }
                return this.transformApiResponse(apiResultat, course);
              })
            );
          }),
          catchError((err) => {
            console.error(`Error fetching resultat ${id}:`, err);
            return of(undefined);
          })
        );
    }
    return of(undefined);
  }

  // GET /api/v1/resultat
  list(): Observable<Resultat[]> {
    if (USE_SERVER) {
      return this.http
        .get<ResultatApiResponse[]>(this.apiUrl, { headers: this.getNgrokHeaders() })
        .pipe(
          switchMap((apiResultats) => {
            // Fetch all unique course IDs (API uses courseId)
            const courseIds = [...new Set(apiResultats.map((r) => String((r as any).courseId ?? '')))].filter(Boolean);
            // Fetch all courses in parallel
            const courseRequests = courseIds.map((id) =>
              this.courseService
                .getById(id)
                .pipe(catchError(() => of<Course | undefined>(undefined)))
            );

            return forkJoin(courseRequests).pipe(
              map((courses) => {
                const courseMap = new Map<string, Course>();
                courseIds.forEach((id, index) => {
                  const course = courses[index];
                  if (course) {
                    courseMap.set(id, course);
                  }
                });

                return apiResultats
                  .map((apiResultat) => {
                    const courseId = String((apiResultat as any).courseId ?? '');
                    const course = courseMap.get(courseId);
                    if (!course) {
                      return null;
                    }
                    return this.transformApiResponse(apiResultat, course);
                  })
                  .filter((r): r is Resultat => r !== null);
              }),
              catchError((err) => {
                console.error('Error fetching resultats:', err);
                return of([]);
              })
            );
          }),
          catchError((err) => {
            console.error('Error fetching resultats:', err);
            return of([]);
          })
        );
    }
    return of([]);
  }

  // GET raw API responses (ResultatApiResponse[])
  listRaw(): Observable<ResultatApiResponse[]> {
    if (USE_SERVER) {
      return this.http
        .get<ResultatApiResponse[]>(this.apiUrl, { headers: this.getNgrokHeaders() })
        .pipe(
          catchError((err) => {
            console.error('Error fetching raw resultats:', err);
            return of([] as ResultatApiResponse[]);
          })
        );
    }
    return of([] as ResultatApiResponse[]);
  }

  // GET /api/v1/resultat/course/{courseId}
  getByCourseId(courseId: string): Observable<Resultat | undefined> {

    return this.http
      .get<any>(`${this.apiUrl}/course/${courseId}`, {
        headers: this.getNgrokHeaders(),
      })
      .pipe(
        switchMap((raw) => {
          // Debug raw response shape to help detect API changes
          console.debug(`ResultatService.getByCourseId(${courseId}) raw:`, raw);
          // Handle common variants of server responses:
          // - { message: '...' } -> no resultat
          // - { id: ..., ordreArrivee: '...' } -> single resultat
          // - [ { ... } ] -> array of resultats (pick first)
          // - { content: [...] } -> take first content

          if (!raw) return of<Resultat | undefined>(undefined);

          // message-only response -> no resultat
          if (typeof raw === 'object' && 'message' in raw && !('id' in raw) && !('ordreArrivee' in raw)) {
            return of<Resultat | undefined>(undefined);
          }

          let apiResultat: ResultatApiResponse | undefined;

          if (Array.isArray(raw)) {
            apiResultat = raw.length > 0 ? (raw[0] as ResultatApiResponse) : undefined;
          } else if (raw && typeof raw === 'object') {
            if ('id' in raw || 'ordreArrivee' in raw) {
              apiResultat = raw as ResultatApiResponse;
            } else if ('content' in raw && Array.isArray(raw.content) && raw.content.length > 0) {
              apiResultat = raw.content[0] as ResultatApiResponse;
            } else if ('data' in raw && raw.data && typeof raw.data === 'object') {
              apiResultat = raw.data as ResultatApiResponse;
            }
          }

          if (!apiResultat) return of<Resultat | undefined>(undefined);

          return this.courseService.getById(courseId).pipe(
            map((course) => {
              if (!course) {
                return undefined;
              }
              return this.transformApiResponse(apiResultat!, course);
            })
          );
        }),
        catchError((err) => {
          // If the backend ever responds with 404 here, also treat as "no resultat".
          if (err?.status === 404) {
            return of(undefined);
          }

          console.error(`Error fetching resultat for course ${courseId}:`, err);
          return of(undefined);
        })
      );
  }

  // POST /api/v1/resultat
  create(payload: CreateResultatPayload): Observable<Resultat> {
    return this.http
      .post<ResultatApiResponse>(this.apiUrl, payload, { headers: this.getNgrokHeaders() })
      .pipe(
        switchMap((apiResultat) => {
          const courseId = String(payload.courseId);
          return this.courseService.getById(courseId).pipe(
            map((course) => {
              if (!course) {
                throw new Error('Course not found');
              }
              return this.transformApiResponse(apiResultat, course);
            })
          );
        }),
        catchError((err) => {
          console.error('Error creating resultat:', err);
          throw err;
        })
      );
  }

  // PUT /api/v1/resultat/{id}
  update(id: string, payload: Partial<CreateResultatPayload>): Observable<Resultat | undefined> {
    if (USE_SERVER) {
      return this.http
        .put<ResultatApiResponse>(`${this.apiUrl}/${id}`, payload, {
          headers: this.getNgrokHeaders(),
        })
        .pipe(
          switchMap((apiResultat) => {
            const courseId = String((apiResultat as any).courseId ?? '');

            return this.courseService.getById(courseId).pipe(
              map((course) => {
                if (!course) {
                  return undefined;
                }
                return this.transformApiResponse(apiResultat, course);
              })
            );
          }),
          catchError((err) => {
            console.error(`Error updating resultat ${id}:`, err);
            return of(undefined);
          })
        );
    }
    throw new Error('Server mode is required');
  }

  // DELETE /api/v1/resultat/{id}
  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 resultat ${id}:`, err);
            return of(false);
          })
        );
    }
    throw new Error('Server mode is required');
  }

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

  private transformApiResponse(apiResultat: ResultatApiResponse, course: Course): Resultat {
    return {
      id: String(apiResultat.id),
      course,
      // API now returns 'ordreArrivee' as CSV/string; normalize to number[]
      ordreArrivee: apiResultat.ordreArrivee,
      statut: apiResultat.statut,
      // dead-heat not provided by new API shape — default to empty
      chevauxDeadHeat: [],
      // Financial fields may not be present in new API; default to 0
      totalMises: (apiResultat as any).totalMises ?? 0,
      masseAPartager: (apiResultat as any).masseAPartager ?? 0,
      prelevementsLegaux: (apiResultat as any).prelevementsLegaux ?? 0,
      montantRembourse: (apiResultat as any).montantRembourse ?? 0,
      montantCagnotte: (apiResultat as any).montantCagnotte ?? 0,
      adeadHeat: (apiResultat as any).adeadHeat ?? false,
      createdAt: apiResultat.createdAt,
      updatedAt: apiResultat.updatedAt,
    };
  }
}
