import { Injectable } from '@angular/core';
import { LoginResponse, UserProfile } from '../../models/auth/auth.model';

type StorageType = 'local' | 'session';

@Injectable({ providedIn: 'root' })
export class TokenStorageService {
  private readonly accessTokenKey = 'master-admin-access-token';
  private readonly refreshTokenKey = 'master-admin-refresh-token';
  private readonly accessTokenExpiresOnKey = 'master-admin-access-token-expires-on';
  private readonly refreshTokenExpiresOnKey = 'master-admin-refresh-token-expires-on';
  private readonly userKey = 'master-admin-user';

  saveAuth(response: LoginResponse, rememberMe: boolean): void {
    this.clearAuth();
    const selectedStorage = rememberMe ? localStorage : sessionStorage;

    if (response.accessToken) {
      selectedStorage.setItem(this.accessTokenKey, response.accessToken);
    }

    if (response.refreshToken) {
      selectedStorage.setItem(this.refreshTokenKey, response.refreshToken);
    }

    if (response.accessTokenExpiresOn) {
      selectedStorage.setItem(this.accessTokenExpiresOnKey, response.accessTokenExpiresOn);
    }

    if (response.refreshTokenExpiresOn) {
      selectedStorage.setItem(this.refreshTokenExpiresOnKey, response.refreshTokenExpiresOn);
    }

    const user = this.buildUserProfile(response);
    if (user) {
      selectedStorage.setItem(this.userKey, JSON.stringify(user));
    }
  }

  clearAuth(): void {
    this.removeFromStorage(localStorage);
    this.removeFromStorage(sessionStorage);
  }

  getAccessToken(): string | null {
    return this.getByPriority(this.accessTokenKey);
  }

  getRefreshToken(): string | null {
    return this.getByPriority(this.refreshTokenKey);
  }

  getAccessTokenExpiresOn(): string | null {
    return this.getByPriority(this.accessTokenExpiresOnKey);
  }

  getRefreshTokenExpiresOn(): string | null {
    return this.getByPriority(this.refreshTokenExpiresOnKey);
  }

  getUser(): UserProfile | null {
    const raw = this.getByPriority(this.userKey);

    if (!raw) {
      return null;
    }

    try {
      return JSON.parse(raw) as UserProfile;
    } catch {
      this.clearAuth();
      return null;
    }
  }

  getStorageType(): 'local' | 'session' | null {
    if (this.hasAnyAuthKey(sessionStorage)) {
      return 'session';
    }

    if (this.hasAnyAuthKey(localStorage)) {
      return 'local';
    }

    return null;
  }

  isAccessTokenExpired(): boolean {
    return this.isExpired(this.getAccessTokenExpiresOn());
  }

  isRefreshTokenExpired(): boolean {
    return this.isExpired(this.getRefreshTokenExpiresOn());
  }

  private getByPriority(key: string): string | null {
    const fromSession = sessionStorage.getItem(key);
    if (fromSession !== null) {
      return fromSession;
    }

    return localStorage.getItem(key);
  }

  private hasAnyAuthKey(storage: Storage): boolean {
    return [
      this.accessTokenKey,
      this.refreshTokenKey,
      this.accessTokenExpiresOnKey,
      this.refreshTokenExpiresOnKey,
      this.userKey,
    ].some((key) => storage.getItem(key) !== null);
  }

  private removeFromStorage(storage: Storage): void {
    storage.removeItem(this.accessTokenKey);
    storage.removeItem(this.refreshTokenKey);
    storage.removeItem(this.accessTokenExpiresOnKey);
    storage.removeItem(this.refreshTokenExpiresOnKey);
    storage.removeItem(this.userKey);
  }

  private isExpired(expiresOn: string | null): boolean {
    if (!expiresOn) {
      return true;
    }

    const parsedExpiry = Date.parse(expiresOn);

    if (Number.isNaN(parsedExpiry)) {
      return true;
    }

    return parsedExpiry <= Date.now();
  }
  private buildUserProfile(response: LoginResponse): UserProfile | null {
    if (response.user) {
      return response.user;
    }

    if (response.userId || response.email) {
      return {
        id: response.userId ?? '',
        email: response.email ?? '',
        roles: response.roles,
      };
    }

    return null;
  }
}
