import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { TokenService } from './token.service';
import {
  LoginRequest,
  LoginResponse,
  RegisterRequest,
  RegisterResponse,
  TokenValidationRequest,
  TokenValidationResponse,
  RefreshTokenRequest,
  TokenPair,
  LogoutRequest,
  ApiResponse,
  ApiError,
  PasswordResetRequest,
  PasswordResetConfirmRequest,
  ChangePasswordRequest,
  EmailVerificationRequest,
  ResendVerificationRequest,
  User,
  TwoFactorSetupResponse,
  TwoFactorVerifyRequest,
  TwoFactorStatusResponse
} from '../models/auth.models';

@Injectable({
  providedIn: 'root'
})
export class AuthHttpService {
  private baseUrl = '';

  constructor(
    private http: HttpClient,
    private tokenService: TokenService
  ) {}

  /**
   * Set the base URL for the auth service
   */
  setBaseUrl(url: string): void {
    this.baseUrl = url.replace(/\/$/, ''); // Remove trailing slash
  }

  /**
   * Get API URL with version prefix
   */
  private getApiUrl(path: string): string {
    return `${this.baseUrl}/api/v1${path}`;
  }

  /**
   * Get HTTP headers with authorization if available
   */
  private getHeaders(includeAuth = true): HttpHeaders {
    let headers = new HttpHeaders({
      'Content-Type': 'application/json'
    });

    if (includeAuth) {
      const authHeader = this.tokenService.getAuthorizationHeader();
      if (authHeader) {
        headers = headers.set('Authorization', authHeader);
      }
    }

    return headers;
  }

  /**
   * Handle HTTP errors and extract API error information
   */
  private handleError(error: any): Observable<never> {
    let apiError: ApiError;

    if (error.error && typeof error.error === 'object') {
      apiError = error.error;
    } else {
      apiError = {
        error: error.message || 'An unknown error occurred'
      };
    }

    return throwError(() => apiError);
  }

  // Authentication Endpoints

  /**
   * Register a new user
   */
  register(request: RegisterRequest): Observable<RegisterResponse> {
    return this.http.post<RegisterResponse>(
      this.getApiUrl('/auth/register'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Login with email and password
   */
  login(request: LoginRequest): Observable<LoginResponse> {
    return this.http.post<LoginResponse>(
      this.getApiUrl('/auth/login'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Refresh access token
   */
  refreshToken(request: RefreshTokenRequest): Observable<TokenPair> {
    return this.http.post<TokenPair>(
      this.getApiUrl('/auth/refresh'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Validate token (for API Gateway)
   */
  validateToken(request: TokenValidationRequest): Observable<TokenValidationResponse> {
    return this.http.post<TokenValidationResponse>(
      this.getApiUrl('/auth/validate'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Logout user
   */
  logout(request?: LogoutRequest): Observable<ApiResponse> {
    return this.http.post<ApiResponse>(
      this.getApiUrl('/auth/logout'),
      request || {},
      { headers: this.getHeaders() }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Get current user information
   */
  getCurrentUser(): Observable<User> {
    return this.http.get<{ user: User }>(
      this.getApiUrl('/auth/me'),
      { headers: this.getHeaders() }
    ).pipe(
      map(response => response.user),
      catchError(this.handleError)
    );
  }

  // User Management Endpoints

  /**
   * Get user profile
   */
  getUserProfile(): Observable<User> {
    return this.http.get<{ user: User }>(
      this.getApiUrl('/users/profile'),
      { headers: this.getHeaders() }
    ).pipe(
      map(response => response.user),
      catchError(this.handleError)
    );
  }

  /**
   * Update user profile
   */
  updateUserProfile(updates: Partial<User>): Observable<User> {
    return this.http.put<{ user: User }>(
      this.getApiUrl('/users/profile'),
      updates,
      { headers: this.getHeaders() }
    ).pipe(
      map(response => response.user),
      catchError(this.handleError)
    );
  }

  /**
   * Change password
   */
  changePassword(request: ChangePasswordRequest): Observable<ApiResponse> {
    return this.http.post<ApiResponse>(
      this.getApiUrl('/users/change-password'),
      request,
      { headers: this.getHeaders() }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Request password reset
   */
  forgotPassword(request: PasswordResetRequest): Observable<ApiResponse> {
    return this.http.post<ApiResponse>(
      this.getApiUrl('/users/forgot-password'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Reset password with token
   */
  resetPassword(request: PasswordResetConfirmRequest): Observable<ApiResponse> {
    return this.http.post<ApiResponse>(
      this.getApiUrl('/users/reset-password'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Verify email with token
   */
  verifyEmail(request: EmailVerificationRequest): Observable<ApiResponse> {
    return this.http.post<ApiResponse>(
      this.getApiUrl('/users/verify-email'),
      request,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Resend email verification
   */
  resendEmailVerification(request?: ResendVerificationRequest): Observable<ApiResponse> {
    const url = request 
      ? this.getApiUrl('/users/resend-verification')
      : this.getApiUrl('/users/resend-verification');
    
    const body = request || {};
    const headers = request ? this.getHeaders(false) : this.getHeaders();

    return this.http.post<ApiResponse>(url, body, { headers }).pipe(
      catchError(this.handleError)
    );
  }

  // Two-Factor Authentication

  /**
   * Setup 2FA for user
   */
  setup2FA(): Observable<TwoFactorSetupResponse> {
    return this.http.post<TwoFactorSetupResponse>(
      this.getApiUrl('/users/2fa/setup'),
      {},
      { headers: this.getHeaders() }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Verify 2FA setup
   */
  verify2FASetup(request: TwoFactorVerifyRequest): Observable<ApiResponse> {
    return this.http.post<ApiResponse>(
      this.getApiUrl('/users/2fa/verify'),
      request,
      { headers: this.getHeaders() }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Disable 2FA
   */
  disable2FA(): Observable<ApiResponse> {
    return this.http.delete<ApiResponse>(
      this.getApiUrl('/users/2fa'),
      { headers: this.getHeaders() }
    ).pipe(
      catchError(this.handleError)
    );
  }

  /**
   * Check 2FA status
   */
  get2FAStatus(): Observable<TwoFactorStatusResponse> {
    return this.http.get<TwoFactorStatusResponse>(
      this.getApiUrl('/security/2fa/status'),
      { headers: this.getHeaders() }
    ).pipe(
      catchError(this.handleError)
    );
  }

  // Health Check

  /**
   * Check service health
   */
  healthCheck(): Observable<any> {
    return this.http.get(
      `${this.baseUrl}/health`,
      { headers: this.getHeaders(false) }
    ).pipe(
      catchError(this.handleError)
    );
  }
}