import { Injectable, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of, forkJoin } from 'rxjs';
import { map, catchError, switchMap } from 'rxjs/operators';
import { Hippodrome } from '../interfaces/hippodrome';
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 { ServicesUtils } from './services-utils';

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

@Injectable({ providedIn: 'root' })
export class HippodromeService {
  private apiUrl = environment.apiBaseUrl + API_BASE;
  private store = signal<Hippodrome[]>([]);


  constructor(private http: HttpClient, private paginatedHttp: PaginatedHttpService, private servicesUtils:ServicesUtils) {}

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

  // LISTE — supporte client & serveur
  list(
    params: ListParams,
    usePaginationEndpoint: boolean = true
  ): Observable<PagedResult<Hippodrome>> {
    const hippodromeList =  this.http.get<PagedResult<Hippodrome>>(this.apiUrl, {
      headers: this.getNgrokHeaders(),
      params: this.servicesUtils.getParamsFromModel(params)
    })
    return hippodromeList;
  }

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

    // Search filter
    const q = (params.search ?? '').toLowerCase();
    if (q) {
      filtered = filtered.filter(
        (h) =>
          h.nom.toLowerCase().includes(q) ||
          h.ville.toLowerCase().includes(q) ||
          h.pays.toLowerCase().includes(q)
      );
    }

    // Sort
    if (params.sortKey && params.sortDir) {
      const { sortKey, sortDir } = params;
      filtered.sort((a: any, b: any) => {
        const va = a[sortKey!],
          vb = b[sortKey!];
        let cmp: number;

        if (typeof va === 'number' && typeof vb === 'number') {
          cmp = va - vb;
        } else {
          const sa = va == null ? '' : String(va);
          const sb = vb == null ? '' : String(vb);
          cmp = sa.localeCompare(sb, 'fr', { numeric: true, sensitivity: 'base' });
        }

        return sortDir === 'asc' ? cmp : -cmp;
      });
    }

    return filtered;
  }

  // READ
  getById(id: string): Observable<Hippodrome | undefined> {
    if (USE_SERVER) {
      return this.http
        .get<Hippodrome>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() })
        .pipe(
          catchError((err) => {
            console.error(`Error fetching hippodrome ${id}:`, err);
            return of(this.store().find((h) => h.id === id));
          })
        );
    }
    const found = this.store().find((h) => h.id === id);
    return of(found);
  }

  // CREATE
  create(payload: Omit<Hippodrome, 'id'>): Observable<Hippodrome> {
    if (USE_SERVER) {
      return this.http
        .post<Hippodrome>(this.apiUrl, payload, { headers: this.getNgrokHeaders() })
        .pipe(
          catchError((err) => {
            console.error('Error creating hippodrome:', err);
            const item: Hippodrome = { id: crypto.randomUUID(), ...payload };
            this.store.set([item, ...this.store()]);
            return of(item);
          })
        );
    }
    const item: Hippodrome = { id: crypto.randomUUID(), ...payload };
    this.store.set([item, ...this.store()]);
    return of(item);
  }

  // UPDATE
  update(id: string, payload: Partial<Hippodrome>): Observable<Hippodrome | undefined> {
    if (USE_SERVER) {
      return this.http
        .put<Hippodrome>(`${this.apiUrl}/${id}`, payload, { headers: this.getNgrokHeaders() })
        .pipe(
          catchError((err) => {
            console.error(`Error updating hippodrome ${id}:`, err);
            let updated: Hippodrome | undefined;
            this.store.set(
              this.store().map((h) => {
                if (h.id === id) {
                  updated = { ...h, ...payload };
                  return updated;
                }
                return h;
              })
            );
            return of(updated);
          })
        );
    }
    let updated: Hippodrome | undefined;
    this.store.set(
      this.store().map((h) => {
        if (h.id === id) {
          updated = { ...h, ...payload };
          return updated;
        }
        return h;
      })
    );
    return of(updated);
  }

  // DELETE
  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 hippodrome ${id}:`, err);
            const before = this.store().length;
            this.store.set(this.store().filter((h) => h.id !== id));
            return of(this.store().length < before);
          })
        );
    }
    const before = this.store().length;
    this.store.set(this.store().filter((h) => h.id !== id));
    return of(this.store().length < before);
  }

  // GET by ville
  getByVille(ville: string): Observable<Hippodrome[]> {
    if (USE_SERVER) {
      return this.http
        .get<Hippodrome[]>(`${this.apiUrl}/ville/${encodeURIComponent(ville)}`, {
          headers: this.getNgrokHeaders(),
        })
        .pipe(
          catchError((err) => {
            console.error(`Error fetching hippodromes by ville ${ville}:`, err);
            return of(this.store().filter((h) => h.ville === ville));
          })
        );
    }
    return of(this.store().filter((h) => h.ville === ville));
  }

  // SEARCH by query (q parameter)
  search(query: string): Observable<Hippodrome[]> {
    if (USE_SERVER) {
      return this.http
        .get<Hippodrome[]>(`${this.apiUrl}/search`, {
          params: { nom: query.trim() },
          headers: this.getNgrokHeaders(),
        })
        .pipe(
          catchError((err) => {
            console.error(`Error searching hippodromes with query ${query}:`, err);
            const q = query.toLowerCase();
            return of(
              this.store().filter(
                (h) =>
                  h.nom.toLowerCase().includes(q) ||
                  h.ville.toLowerCase().includes(q) ||
                  h.pays.toLowerCase().includes(q)
              )
            );
          })
        );
    }
    const q = query.toLowerCase();
    return of(
      this.store().filter(
        (h) =>
          h.nom.toLowerCase().includes(q) ||
          h.ville.toLowerCase().includes(q) ||
          h.pays.toLowerCase().includes(q)
      )
    );
  }

  // GET actifs
  getActifs(): Observable<Hippodrome[]> {
    if (USE_SERVER) {
      return this.http
        .get<Hippodrome[]>(`${this.apiUrl}/actifs`, { headers: this.getNgrokHeaders() })
        .pipe(
          catchError((err) => {
            console.error('Error fetching active hippodromes:', err);
            return of(this.store().filter((h) => h.actif));
          })
        );
    }
    return of(this.store().filter((h) => h.actif));
  }
}
