// import { ADMIN_API_ROUTES } from '@/modules/admin/constants';
// import { SCHOOLS_API_ROUTES } from '@/modules/schools/constants';
// import { ISchoolMeResponse } from '@/modules/schools/models';
// import { TEACHERS_API_ROUTES } from '@/modules/teachers/constants';
import { HttpClient } from '@angular/common/http';
import { computed, inject, Injectable, signal } from '@angular/core';
import { Router } from '@angular/router';
import { CookieService } from 'ngx-cookie-service';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { catchError, finalize, tap } from 'rxjs/operators';
import config from 'src/config';
import { COOKIE_KEYS, LOCAL_STORAGE_KEYS } from '../../../assets/constants';
import {
  IAuthAccountResponse,
  IAuthResponse,
  IUserLoginInfo,
  LoginCredentials,
  Maybe,
  TRoles,
} from '../models';
import { CaptchaService } from './captcha.service';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor() {
    this.initializeAuth();
  }

  private readonly http = inject(HttpClient);
  private readonly router = inject(Router);
  private readonly cookieService = inject(CookieService);
  private captchaService = inject(CaptchaService);

  private readonly currentAccountSubject = new BehaviorSubject<Maybe<IAuthAccountResponse>>(null);
  private readonly isLoadingSubject = new BehaviorSubject<boolean>(false);

  readonly currentUser$ = this.currentAccountSubject.asObservable();
  readonly isLoading$ = this.isLoadingSubject.asObservable();

  // Signals for reactive state management
  // readonly currentUser = signal<Maybe<User>>(null);
  readonly currentAccount = signal<Maybe<IAuthAccountResponse>>(null);
  readonly isLoading = signal<boolean>(false);
  readonly token = signal<Maybe<string>>(null);
  readonly refreshToken = signal<Maybe<string>>(null);
  readonly isAuthenticated = computed(() => {
    return Boolean(this.token());
  });
  readonly userRole = computed(() => this.currentAccount()?.type);

  private initializeAuth(): void {
    const token = localStorage.getItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN);

    const accountData = localStorage.getItem(LOCAL_STORAGE_KEYS.USER_DATA);

    if (token && accountData) {
      try {
        this.token.set(token);
        const account = JSON.parse(accountData) as IAuthAccountResponse;
        this.setCurrentUser(account);
      } catch (error) {
        console.error('Error parsing stored user data:', error);
        this.logout();
      }
    }
  }

  login(credentials: LoginCredentials): Observable<IAuthResponse> {
    const { username, password, captcha } = credentials;
    this.isLoading.set(true);
    this.isLoadingSubject.next(true);
    const baseHeaders = this.captchaService.buildCaptchaHeaders({}, captcha);

    return this.http
      .post<IAuthResponse>(
        '/api/v1/auth/login',
        { username, password, isPos: config.isPosApplication },
        {
          headers: baseHeaders,
        },
      )
      .pipe(
        tap((response) => {
          this.handleAuthSuccess(response);
          this.refreshCookies();
          return response;
        }),
        catchError((error) => {
          console.error('Login error:', error);
          this.isLoadingSubject.next(false);
          throw error;
        }),
        finalize(() => {
          this.isLoading.set(false);
        }),
      );
  }

  logout(): void {
    localStorage.removeItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN);
    localStorage.removeItem(LOCAL_STORAGE_KEYS.USER_DATA);
    localStorage.removeItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN);
    this.refreshCookies();

    this.setCurrentUser(null);
    this.router.navigate(['/auth']);
  }

  refreshCookies() {
    this.cookieService.set(COOKIE_KEYS.POS_ID, '', new Date());
    this.cookieService.set(COOKIE_KEYS.ACCESS_TOKEN, '', new Date());
  }

  doRefreshToken(): Observable<IAuthResponse> {
    const refreshToken = this.getRefreshToken();
    if (!refreshToken) {
      this.logout();
      return throwError(() => new Error('No refresh token available'));
    }

    return this.http.post<IAuthResponse>('/api/auth/refresh', { refreshToken }).pipe(
      tap((response) => {
        this.handleAuthSuccess(response);
      }),
      catchError((error) => {
        console.error('Token refresh error:', error);
        this.logout();
        return throwError(() => error);
      }),
    );
  }

  getInfo(role: TRoles): Observable<Partial<IUserLoginInfo>> {
    // if (this.modulesGetInfoRoutes[role]) {
    //   return this.http.get<any>(this.modulesGetInfoRoutes[role]).pipe(
    //     map((data) => {
    //       switch (role) {
    //         case 'SCHOOL':
    //           return this.prepareUserInfoBasedOnRole(role, data as ISchoolMeResponse);
    //         default:
    //           return data as Partial<IUserLoginInfo>;
    //       }
    //     }),
    //     catchError((err) => {
    //       console.error('GetInfo error:', err);
    //       return throwError(() => err);
    //     }),
    //   );
    // }

    return throwError(() => new Error('متاسفانه مشکلی پیش آمده'));
  }

  // prepareUserInfoBasedOnRole(role: TRoles, info: ISchoolMeResponse): Partial<IUserLoginInfo> {
  //   if (role === 'SCHOOL') {
  //     return {
  //       username: info.username,
  //       email: info.managerInfo.email,
  //       mobile: info.managerInfo.mobile,
  //     };
  //   }
  //   return {};
  // }

  /**
   * Get current access token
   */
  getToken(): Maybe<string> {
    return localStorage.getItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN);
  }

  /**
   * Get current refresh token
   */
  getRefreshToken(): Maybe<string> {
    return localStorage.getItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN);
  }

  /**
   * Check if token is expired (optional - requires JWT parsing)
   */
  isTokenExpired(): boolean {
    const token = this.getToken();
    if (!token) return true;

    try {
      // Parse JWT token to check expiration
      const payload = JSON.parse(atob(token.split('.')[1]));
      const currentTime = Math.floor(Date.now() / 1000);
      return payload.exp < currentTime;
    } catch (error) {
      console.error('Error parsing token:', error);
      return true;
    }
  }

  /**
   * Check if refresh token is expired
   */
  isRefreshTokenExpired(): boolean {
    const refreshToken = this.getRefreshToken();
    if (!refreshToken) return true;

    try {
      // Parse JWT refresh token to check expiration
      const payload = JSON.parse(atob(refreshToken.split('.')[1]));
      const currentTime = Math.floor(Date.now() / 1000);
      return payload.exp < currentTime;
    } catch (error) {
      console.error('Error parsing refresh token:', error);
      return true;
    }
  }

  hasRole(role: TRoles): boolean {
    return this.currentAccount()?.type === role;
  }

  hasAnyRole(roles: TRoles[]): boolean {
    const currentRole = this.currentAccount()?.type;
    return currentRole ? roles.includes(currentRole) : false;
  }

  hasPermission(permission: string): boolean {
    const user = this.currentAccount();
    if (!user) return false;

    return true;
    // return user.permissions.some(
    //   (p) => p.name === permission || `${p.resource}:${p.action}` === permission,
    // );
  }

  canAccess(requiredRoles?: TRoles[], requiredPermissions?: string[]): boolean {
    if (!this.isAuthenticated()) return false;

    if (requiredRoles && requiredRoles.length > 0) {
      if (!this.hasAnyRole(requiredRoles)) return false;
    }

    if (requiredPermissions && requiredPermissions.length > 0) {
      return requiredPermissions.every((permission) => this.hasPermission(permission));
    }

    return true;
  }

  private handleAuthSuccess(response: IAuthResponse): void {
    localStorage.setItem(LOCAL_STORAGE_KEYS.AUTH_TOKEN, response.accessToken);
    this.token.set(response.accessToken);
    this.refreshToken.set(response.refreshToken);
    localStorage.setItem(LOCAL_STORAGE_KEYS.REFRESH_TOKEN, response.refreshToken);

    this.setCurrentUser(response.account);
    this.isLoadingSubject.next(false);

    // Navigate based on user role
    // this.navigateByRole(response.user.role);
  }

  private setCurrentUser(account: Maybe<IAuthAccountResponse>): void {
    this.currentAccount.set(account);
    this.currentAccountSubject.next(account);
    localStorage.setItem(LOCAL_STORAGE_KEYS.USER_DATA, JSON.stringify(account));
  }
}
