import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { User } from '../interfaces/user';
import { PaginatedHttpService } from '@shared/paging/paginated-http.service';
import { ListParams, PagedResult, SortDir } from '@shared/paging/paging';
import { normalizePage } from '@shared/paging/normalize-page';
import { environment } from 'src/environments/environment.development';

const USE_SERVER = true;
const API_BASE = '/api/v1/users';

// Backend payload
interface UserApiResponse {
  id: number;
  nom: string;
  prenom: string;
  identifiant: string;
  password?: string;
  matriculeAgent: string;
  roleId: number;
  restrictionConnexion: boolean;
  restrictionAutomatique: boolean;
  nombreIpAutorise: number;
  nombreIpAutoAutorise: number;
  statut: string;
  derniereConnexion?: string;
  createdAt?: string;
  updatedAt?: string;
}

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

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

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

  private transform(api: UserApiResponse): User {
    return {
      id: String(api.id),
      nom: api.nom,
      prenom: api.prenom,
      identifiant: api.identifiant,
      // We never expose password back to UI
      matriculeAgent: api.matriculeAgent,
      roleId: String(api.roleId),
      restrictionConnexion: api.restrictionConnexion,
      restrictionAutomatique: api.restrictionAutomatique,
      nombreIpAutorise: api.nombreIpAutorise,
      nombreIpAutoAutorise: api.nombreIpAutoAutorise,
      statut: api.statut,
      derniereConnexion: api.derniereConnexion,
      createdAt: api.createdAt,
      updatedAt: api.updatedAt,
    };
  }

  private transformToApiPayload(user: Partial<User>): Partial<UserApiResponse> {
    return {
      id: user.id ? Number(user.id) : undefined,
      nom: user.nom ?? '',
      prenom: user.prenom ?? '',
      identifiant: user.identifiant ?? '',
      password: user.password,
      matriculeAgent: user.matriculeAgent ?? '',
      roleId: user.roleId ? Number(user.roleId) : 0,
      restrictionConnexion: user.restrictionConnexion ?? false,
      restrictionAutomatique: user.restrictionAutomatique ?? false,
      nombreIpAutorise: user.nombreIpAutorise ?? 0,
      nombreIpAutoAutorise: user.nombreIpAutoAutorise ?? 0,
      statut: user.statut ?? 'Actif',
      derniereConnexion: user.derniereConnexion,
      createdAt: user.createdAt,
      updatedAt: user.updatedAt,
    };
  }

  list(params: ListParams): Observable<PagedResult<User>> {
    if (USE_SERVER) {
      // Backend returns full list; paginate client-side
      return this.http
        .get<UserApiResponse[]>(this.apiUrl, { headers: this.getNgrokHeaders() })
        .pipe(
          map((items) => (items || []).map((u) => this.transform(u))),
          map((users) => {
            const q = (params.search ?? '').toLowerCase();
            let data = users;

            if (q) {
              data = data.filter((u) =>
                [u.nom, u.prenom, u.identifiant, u.matriculeAgent, u.statut]
                  .filter(Boolean)
                  .map((x) => String(x).toLowerCase())
                  .some((s) => s.includes(q))
              );
            }

            if (params.sortKey && params.sortDir) {
              const { sortKey, sortDir } = params as { sortKey: string; sortDir: SortDir };
              const getValue = (obj: any, path: string) =>
                path.split('.').reduce((o, k) => o?.[k], obj);
              data = [...data].sort((a: any, b: any) => {
                const sa = String(getValue(a, sortKey) ?? '');
                const sb = String(getValue(b, sortKey) ?? '');
                const cmp = sa.localeCompare(sb, 'fr', { numeric: true });
                return sortDir === 'asc' ? cmp : -cmp;
              });
            }

            const start = (params.page - 1) * params.size;
            const pageData = data.slice(start, start + params.size);

            return normalizePage<User>(
              { data: pageData, meta: { total: data.length } },
              params.page,
              params.size
            );
          }),
          catchError(() =>
            of(normalizePage<User>({ data: [], meta: { total: 0 } }, params.page, params.size))
          )
        );
    }

    // Fallback should not be used anymore
    return of(normalizePage<User>({ data: [], meta: { total: 0 } }, params.page, params.size));
  }

  create(payload: Omit<User, 'id'>): Observable<User> {
    const body = this.transformToApiPayload(payload);
    return this.http
      .post<UserApiResponse>(this.apiUrl, body, { headers: this.getNgrokHeaders() })
      .pipe(map((res) => this.transform(res)));
  }

  update(id: string, payload: Partial<User>): Observable<User | undefined> {
    const body = this.transformToApiPayload({ ...payload, id });
    return this.http
      .put<UserApiResponse>(`${this.apiUrl}/${id}`, body, { headers: this.getNgrokHeaders() })
      .pipe(
        map((res) => this.transform(res)),
        catchError(() => of(undefined))
      );
  }

  delete(id: string): Observable<boolean> {
    return this.http.delete<void>(`${this.apiUrl}/${id}`, { headers: this.getNgrokHeaders() }).pipe(
      map(() => true),
      catchError(() => of(false))
    );
  }
}
