import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { Permission, Role } from '../interfaces/role';
import { normalizePage } from '@shared/paging/normalize-page';
import { ListParams, PagedResult } from '@shared/paging/paging';
import { environment } from 'src/environments/environment.development';

const USE_SERVER = true;
const ROLES_API_BASE = '/api/v1/roles';
const PERMISSIONS_API_BASE = '/api/v1/permissions';

// API Response interfaces
interface PermissionApiResponse {
  id: number;
  name: string;
  description?: string;
}

interface RoleApiResponse {
  id: number;
  name: string;
  description?: string;
  permissions?: PermissionApiResponse[];
  createdAt?: string;
  updatedAt?: string;
}

@Injectable({ providedIn: 'root' })
export class RoleService {
  private rolesUrl = environment.apiBaseUrl + ROLES_API_BASE;
  private permissionsUrl = environment.apiBaseUrl + PERMISSIONS_API_BASE;

  constructor(private http: HttpClient) {}

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

  // Transform API response to Permission
  private transformPermission(api: PermissionApiResponse): Permission {
    return {
      id: String(api.id),
      name: api.name,
      description: api.description,
    };
  }

  // Transform API response to Role
  private transformRole(api: RoleApiResponse): Role {
    return {
      id: String(api.id),
      name: api.name,
      description: api.description,
      permissions: (api.permissions || []).map((p) => this.transformPermission(p)),
      createdAt: api.createdAt,
      updatedAt: api.updatedAt,
    };
  }

  // Transform Role to API payload
  private transformRoleToApi(role: Partial<Role>): any {
    return {
      id: role.id ? Number(role.id) : undefined,
      name: role.name ?? '',
      description: role.description,
      permissions: (role.permissions || []).map((p) => ({
        id: p.id ? Number(p.id) : undefined,
        name: p.name,
        description: p.description,
      })),
    };
  }

  // Transform Permission to API payload
  private transformPermissionToApi(perm: Partial<Permission>): any {
    return {
      id: perm.id ? Number(perm.id) : undefined,
      name: perm.name ?? '',
      description: perm.description,
    };
  }

  // Helpers
  private buildParams(params: ListParams): HttpParams {
    let httpParams = new HttpParams()
      .set('page', String(params.page - 1))
      .set('size', String(params.size));
    if (params.search) {
      httpParams = httpParams.set('search', params.search);
    }
    if (params.sortKey && params.sortDir) {
      httpParams = httpParams.set('sort', `${params.sortKey},${params.sortDir}`);
    }
    return httpParams;
  }

  /**
   * LIST roles – supports both backend pagination and fallback to simple GET all
   */
  list(params: ListParams): Observable<PagedResult<Role>> {
    if (USE_SERVER) {
      return this.http
        .get<RoleApiResponse[]>(this.rolesUrl, {
          headers: this.getNgrokHeaders(),
          params: this.buildParams(params),
        })
        .pipe(
          map((data) => {
            const roles = (data || []).map((r) => this.transformRole(r));
            return normalizePage<Role>(
              { data: roles, meta: { total: roles.length } },
              params.page,
              params.size
            );
          }),
          catchError((err) => {
            console.error('Error fetching roles:', err);
            return of(
              normalizePage<Role>({ data: [], meta: { total: 0 } }, params.page, params.size)
            );
          })
        );
    }

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

  /**
   * LIST all permissions
   */
  allPermissions(): Observable<Permission[]> {
    if (USE_SERVER) {
      return this.http
        .get<PermissionApiResponse[]>(this.permissionsUrl, { headers: this.getNgrokHeaders() })
        .pipe(
          map((res) => (res || []).map((p) => this.transformPermission(p))),
          catchError((err) => {
            console.error('Error fetching permissions:', err);
            return of([]);
          })
        );
    }
    return of([]);
  }

  /**
   * CREATE role
   */
  create(payload: Omit<Role, 'id'>): Observable<Role> {
    const apiPayload = this.transformRoleToApi(payload);
    return this.http
      .post<RoleApiResponse>(this.rolesUrl, apiPayload, { headers: this.getNgrokHeaders() })
      .pipe(
        map((r) => this.transformRole(r)),
        catchError((err) => {
          console.error('Error creating role:', err);
          throw err;
        })
      );
  }

  /**
   * UPDATE role
   */
  update(id: string, payload: Partial<Role>): Observable<Role | undefined> {
    const apiPayload = this.transformRoleToApi(payload);
    return this.http
      .put<RoleApiResponse>(`${this.rolesUrl}/${id}`, apiPayload, {
        headers: this.getNgrokHeaders(),
      })
      .pipe(
        map((r) => this.transformRole(r)),
        catchError((err) => {
          console.error(`Error updating role ${id}:`, err);
          return of(undefined);
        })
      );
  }

  /**
   * DELETE role
   */
  delete(id: string): Observable<{ success: boolean; error?: string }> {
    return this.http
      .delete<void>(`${this.rolesUrl}/${id}`, { headers: this.getNgrokHeaders() })
      .pipe(
        map(() => ({ success: true })),
        catchError((err) => {
          console.error(`Error deleting role ${id}:`, err);
          // Check if error is due to role being used by users
          const errorMessage =
            err?.error?.message ||
            err?.message ||
            (err?.status === 409 || err?.status === 400
              ? 'Ce rôle est utilisé par des utilisateurs et ne peut pas être supprimé'
              : 'Erreur lors de la suppression du rôle');
          return of({ success: false, error: errorMessage });
        })
      );
  }

  // --------------- PERMISSIONS CRUD ----------------

  getPermission(id: string): Observable<Permission | null> {
    return this.http
      .get<PermissionApiResponse>(`${this.permissionsUrl}/${id}`, {
        headers: this.getNgrokHeaders(),
      })
      .pipe(
        map((p) => this.transformPermission(p)),
        catchError((err) => {
          console.error(`Error fetching permission ${id}:`, err);
          return of(null);
        })
      );
  }

  createPermission(payload: Omit<Permission, 'id'>): Observable<Permission> {
    const apiPayload = this.transformPermissionToApi(payload);
    return this.http
      .post<PermissionApiResponse>(this.permissionsUrl, apiPayload, {
        headers: this.getNgrokHeaders(),
      })
      .pipe(
        map((p) => this.transformPermission(p)),
        catchError((err) => {
          console.error('Error creating permission:', err);
          throw err;
        })
      );
  }

  updatePermission(id: string, payload: Partial<Permission>): Observable<Permission | undefined> {
    const apiPayload = this.transformPermissionToApi(payload);
    return this.http
      .put<PermissionApiResponse>(`${this.permissionsUrl}/${id}`, apiPayload, {
        headers: this.getNgrokHeaders(),
      })
      .pipe(
        map((p) => this.transformPermission(p)),
        catchError((err) => {
          console.error(`Error updating permission ${id}:`, err);
          return of(undefined);
        })
      );
  }

  deletePermission(id: string): Observable<{ success: boolean; error?: string }> {
    return this.http
      .delete<void>(`${this.permissionsUrl}/${id}`, { headers: this.getNgrokHeaders() })
      .pipe(
        map(() => ({ success: true })),
        catchError((err) => {
          console.error(`Error deleting permission ${id}:`, err);
          // Check if error is due to permission being used by roles
          const errorMessage =
            err?.error?.message ||
            err?.message ||
            (err?.status === 409 || err?.status === 400
              ? 'Cette permission est utilisée par des rôles et ne peut pas être supprimée'
              : 'Erreur lors de la suppression de la permission');
          return of({ success: false, error: errorMessage });
        })
      );
  }
}
