import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '@environments/environment';
import { catchError, Observable, of, throwError } from 'rxjs';

import {
  Partner,
  CreatePartnerDto,
  UpdatePartnerDto,
  PartnerQuery,
  PaginatedPartners,
  ApiResponse,
  CallbackConfiguration,
  UpdateCallbacksDto,
  ApiKeyResponse,
  PartnerStats
} from '../models/partners-config.model';

@Injectable({ providedIn: 'root' })
export class PartnerConfigService {
  private http = inject(HttpClient);
  private apiUrl = `${environment.localServiceTestApiUrl}/partners/config`;

  // ==================== GESTION DES MARCHANDS (ADMIN) ====================

  /**
   * Créer une config marchand
   */
  createPartnerConfig(createPartnerDto: CreatePartnerDto): Observable<ApiResponse<Partner>> {
    return this.http.post<ApiResponse<Partner>>(`${this.apiUrl}`, createPartnerDto).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Obtenir toutes les une config marchands avec pagination
   */
  findAllPartnersConfig(query: PartnerQuery = new PartnerQuery()): Observable<PaginatedPartners> {
    const params = this.buildQueryParams(query);
    
    return this.http.get<PaginatedPartners>(`${this.apiUrl}`, { params }).pipe(
      catchError(error => {
        console.error('Error loading merchants:', error);
        return of(new PaginatedPartners());
      })
    );
  }

  /**
   * Obtenir une config marchand par son ID
   */
  getPartnerConfigById(merchantId: string): Observable<ApiResponse<Partner>> {
    return this.http.get<ApiResponse<Partner>>(`${this.apiUrl}/${merchantId}`).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Mettre à jour une config marchand
   */
  updatePartnerConfig(merchantId: string, updateData: UpdatePartnerDto): Observable<ApiResponse<Partner>> {
    return this.http.put<ApiResponse<Partner>>(`${this.apiUrl}/${merchantId}`, updateData).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Supprimer une config marchand
   */
  deletePartnerConfig(merchantId: string): Observable<ApiResponse<void>> {
    return this.http.delete<ApiResponse<void>>(`${this.apiUrl}/${merchantId}`).pipe(
      catchError(error => throwError(() => error))
    );
  }

  // ==================== GESTION DES CALLBACKS ====================

  /**
   * Mettre à jour la configuration des callbacks d'un marchand
   */
  updateCallbacksConfig(merchantId: string, updateData: UpdateCallbacksDto): Observable<ApiResponse<Partner>> {
    return this.http.put<ApiResponse<Partner>>(
      `${this.apiUrl}/${merchantId}/callbacks`,
      updateData
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Obtenir la configuration des callbacks d'un marchand
   */
  getCallbacksConfig(merchantId: string): Observable<ApiResponse<CallbackConfiguration>> {
    return this.http.get<ApiResponse<CallbackConfiguration>>(
      `${this.apiUrl}/${merchantId}/callbacks`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Tester un webhook spécifique
   */
  testWebhookConfig(merchantId: string, webhookType: string, payload: any = {}): Observable<ApiResponse<any>> {
    return this.http.post<ApiResponse<any>>(
      `${this.apiUrl}/${merchantId}/callbacks/test/${webhookType}`,
      payload
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Obtenir les logs des webhooks d'un marchand
   */
  getWebhookLogsConfig(merchantId: string, query: any = {}): Observable<ApiResponse<any>> {
    const params = this.buildQueryParams(query);
    return this.http.get<ApiResponse<any>>(
      `${this.apiUrl}/${merchantId}/callbacks/logs`,
      { params }
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  // ==================== GESTION DES STATISTIQUES ====================

  /**
   * Obtenir les statistiques d'un marchand
   */
  getPartnerStats(merchantId: string): Observable<ApiResponse<PartnerStats>> {
    return this.http.get<ApiResponse<PartnerStats>>(
      `${this.apiUrl}/${merchantId}/stats`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Obtenir mes statistiques (marchand connecté)
   */
  getMyStats(): Observable<ApiResponse<PartnerStats>> {
    return this.http.get<ApiResponse<PartnerStats>>(
      `${this.apiUrl}/me/stats`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Obtenir les statistiques globales (admin seulement)
   */
  getGlobalStats(): Observable<ApiResponse<any>> {
    return this.http.get<ApiResponse<any>>(
      `${this.apiUrl}/stats/global`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  // ==================== GESTION DES CLÉS API ====================

  /**
   * Générer de nouvelles clés API pour un marchand
   */
  generateApiKeys(merchantId: string): Observable<ApiResponse<ApiKeyResponse>> {
    return this.http.post<ApiResponse<ApiKeyResponse>>(
      `${this.apiUrl}/${merchantId}/api-keys`,
      {}
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Révoker les clés API d'un marchand
   */
  revokeApiKeys(merchantId: string): Observable<ApiResponse<void>> {
    return this.http.delete<ApiResponse<void>>(
      `${this.apiUrl}/${merchantId}/api-keys`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Régénérer la clé secrète d'un marchand
   */
  regenerateSecretKey(merchantId: string): Observable<ApiResponse<ApiKeyResponse>> {
    return this.http.put<ApiResponse<ApiKeyResponse>>(
      `${this.apiUrl}/${merchantId}/api-keys/regenerate-secret`,
      {}
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  /**
   * Obtenir les clés API d'un marchand
   */
  getApiKeys(merchantId: string): Observable<ApiResponse<ApiKeyResponse>> {
    return this.http.get<ApiResponse<ApiKeyResponse>>(
      `${this.apiUrl}/${merchantId}/api-keys`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }

  // ==================== MÉTHODES UTILITAIRES ====================

  private buildQueryParams(query: any): { [key: string]: string } {
    const params: { [key: string]: string } = {};
    
    Object.keys(query).forEach(key => {
      if (query[key] !== undefined && query[key] !== null && query[key] !== '') {
        params[key] = query[key].toString();
      }
    });
    
    return params;
  }

  /**
   * Valider la configuration d'un marchand
   */
  validatePartnerConfig(merchantId: string): Observable<ApiResponse<{ isValid: boolean; errors: string[] }>> {
    return this.http.get<ApiResponse<{ isValid: boolean; errors: string[] }>>(
      `${this.apiUrl}/${merchantId}/validate`
    ).pipe(
      catchError(error => throwError(() => error))
    );
  }
}