import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import {BehaviorSubject, Observable, throwError} from 'rxjs';
import {catchError, tap} from 'rxjs/operators';
import {environmentProd as env} from '../../environments/environment';
import {Router} from '@angular/router';

export interface LoginCredentials {
  email: string;
  password: string;
}

export interface RegisterData {
  name: string;
  email: string;
  password: string;
  password_confirmation: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  message?: string;
  errors?: any;
}

export interface AuthResponse {
  user: any;
  token: string;
  expires_in?: number;
}

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  protected baseUrl = env.apiUrl || 'http://localhost:8000/api';
  private tokenSubject = new BehaviorSubject<string | null>(this.getStoredToken());
  public token$ = this.tokenSubject.asObservable();

  constructor(protected http: HttpClient, private router: Router) {}

  // Get current token value
  get currentToken(): string | null {
    return this.tokenSubject.value;
  }

  // Check if user is authenticated
  get isAuthenticated(): boolean {
    return !!this.currentToken;
  }

  // Authentication methods
  register(userData: RegisterData): Observable<ApiResponse<AuthResponse>> {
    return this.post<ApiResponse<AuthResponse>>('/auth/register', userData).pipe(
      tap(response => {
        console.log(response)
        if (response.success && response.data?.token) {
          this.setToken(response.data.token);
        }
      })
    );
  }

  login(credentials: LoginCredentials): Observable<ApiResponse<AuthResponse>> {
    return this.post<ApiResponse<AuthResponse>>('/auth/login', credentials).pipe(
      tap(response => {
        if (response.success && response.data?.token) {
          this.setToken(response.data.token);
        }
      })
    );
  }

  logout(): Observable<ApiResponse> {
    return this.post<ApiResponse>('/auth/logout', {}).pipe(
      tap(() => {
        this.removeToken();
      })
    );
  }

  getCurrentUser(): Observable<ApiResponse> {
    return this.get<ApiResponse>('/auth/user');
  }

  refreshToken(): Observable<ApiResponse<AuthResponse>> {
    return this.post<ApiResponse<AuthResponse>>('/auth/refresh', {}).pipe(
      tap(response => {
        if (response.success && response.data?.token) {
          this.setToken(response.data.token);
        }
      })
    );
  }

  // Generic API methods for future use
  getData<T>(endpoint: string): Observable<T> {
    return this.get<T>(endpoint);
  }

  postData<T>(endpoint: string, data: any): Observable<T> {
    return this.post<T>(endpoint, data);
  }

  putData<T>(endpoint: string, data: any): Observable<T> {
    return this.put<T>(endpoint, data);
  }

  deleteData<T>(endpoint: string): Observable<T> {
    return this.delete<T>(endpoint);
  }

  // Generic HTTP methods
  protected get<T>(endpoint: string): Observable<T> {
    return this.http.get<T>(`${this.baseUrl}${endpoint}`, {
      headers: this.getHeaders()
    }).pipe(
      catchError(this.handleError.bind(this))
    );
  }

  protected post<T>(endpoint: string, data: any): Observable<T> {
    return this.http.post<T>(`${this.baseUrl}${endpoint}`, data, {
      headers: this.getHeaders()
    }).pipe(
      catchError(this.handleError.bind(this))
    );
  }

  // Get stored token from localStorage
  private getStoredToken(): string | null {
    if (typeof window !== 'undefined') {
      return localStorage.getItem('auth_token');
    }
    return null;
  }

  // Set token in localStorage and update subject
  private setToken(token: string): void {
    if (typeof window !== 'undefined') {
      localStorage.setItem('auth_token', token);
    }
    this.tokenSubject.next(token);
  }

  // Remove token from localStorage and update subject
  private removeToken(): void {
    if (typeof window !== 'undefined') {
      console.log('?? ?? ??')
      localStorage.removeItem('auth_token');
    }
    this.tokenSubject.next(null);
  }

  // Get HTTP headers with auth token
  private getHeaders(): HttpHeaders {
    let headers = new HttpHeaders({
      //'Content-Type': 'application/json',
      //'Accept': 'application/json'
    });

    const token = this.currentToken;
    if (token) {
      headers = headers.set('Authorization', `Bearer ${token}`);
    }

    return headers;
  }

  // Handle HTTP errors
  private handleError(error: HttpErrorResponse): Observable<never> {
    let errorMessage = 'An unknown error occurred';

    if (error.error instanceof ErrorEvent) {
      // Client-side error
      errorMessage = error.error.message;
    } else {
      // Server-side error
      if (error.status === 401) {
        this.removeToken();
        this.router.navigate(['/login'])
      } else if (error.status === 422) {
        errorMessage = 'Validation error';
      } else if (error.error?.message) {
        errorMessage = error.error.message;
      } else {
        errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
      }
    }

    console.error('API Error:', error);
    return throwError(() => ({...error, userMessage: errorMessage}));
  }

  private put<T>(endpoint: string, data: any): Observable<T> {
    return this.http.put<T>(`${this.baseUrl}${endpoint}`, data, {
      headers: this.getHeaders()
    }).pipe(
      catchError(this.handleError.bind(this))
    );
  }

  private delete<T>(endpoint: string): Observable<T> {
    return this.http.delete<T>(`${this.baseUrl}${endpoint}`, {
      headers: this.getHeaders()
    }).pipe(
      catchError(this.handleError.bind(this))
    );
  }
}
