import { PersistenceV2, Type } from "@kit.ArkUI";
import { contextConstant } from "@kit.AbilityKit";
import { Auth, User } from "@shared/types";
import { RequestHelper } from "@core/network";
import { ContextUtil, PreferencesUtil } from "@core/util";
import { preferences } from "@kit.ArkData";
import { getContainer } from "@core/di";
import { IUserInfoRepository, USER_INFO_REPOSITORY_KEY } from "@shared/contracts";

/**
 * @file 全局用户状态(持久化),提供跨页面共享的响应式状态
 * @author Joker.X
 */

/**
 * AppStorageV2 键名
 */
export const USER_STATE_KEY: string = "user_state";

/**
 * 全局用户状态
 */
@ObservedV2
export class UserState {
  /**
   * 认证信息
   */
  @Type(Auth)
  @Trace
  private auth: Auth = new Auth();
  /**
   * 用户信息
   */
  @Type(User)
  @Trace
  userInfo: User = new User();

  /**
   * token信息
   */
  public token: TokenStore = new TokenStore();

  /**
   * 更新用户登录状态(认证 + 用户信息)
   * @param {Auth} auth - 认证信息
   * @param {User} user - 用户信息
   * @returns {void} 无返回值
   * @example
  * getUserState().updateUserState(new Auth(), new User());
   */
  updateUserState(auth: Auth, user: User): void {
    this.auth = Auth.fromResponse(auth);
    this.userInfo = User.fromResponse(user);
    this.token.saveToken(this.auth.token);
    this.persist();
  }

  /**
   * 更新用户信息
   * @param {User} user - 新的用户信息
   * @returns {void} 无返回值
   * @example
  * getUserState().updateUserInfo(new User({ nickName: "ArkUI" }));
   */
  updateUserInfo(user: User): void {
    this.userInfo = User.fromResponse(user);
    this.persist();
  }

  /**
   * 更新认证信息(例如刷新 token)
   * @param {Auth} auth - 新的认证信息
   * @returns {void} 无返回值
   * @example
  * getUserState().updateAuth(new Auth({ token: "abc" }));
   */
  updateAuth(auth: Auth): void {
    this.auth = Auth.fromResponse(auth);
    this.token.saveToken(this.auth.token);
    this.persist();
  }

  /**
   * 用户登出,清空状态
   * @returns {void} 无返回值
   * @example
  * getUserState().logout();
   */
  logout(): void {
    this.auth = new Auth();
    this.userInfo = new User();
    this.token.clearToken();
    PersistenceV2.remove(USER_STATE_KEY);
  }

  /**
   * 是否需要刷新 token(过期前15分钟)
   * @returns {boolean} 是否需要刷新
   * @example
  * const needRefresh = getUserState().shouldRefreshToken();
   */
  shouldRefreshToken(): boolean {
    if (!this.auth) {
      return false;
    }
    return this.auth.shouldRefresh();
  }

  /**
   * 从网络刷新用户信息
   * @returns {void} 无返回值
   * @example
  * getUserState().refreshUserInfo();
   */
  refreshUserInfo(): void {
    if (!this.isLoggedIn()) {
      return;
    }
    const userInfoRepository = getContainer().tryResolve<IUserInfoRepository>(USER_INFO_REPOSITORY_KEY);
    if (userInfoRepository) {
      RequestHelper.from<User>(userInfoRepository.getPersonInfo())
        .execute()
        .then((userInfo: User): void => {
          this.updateUserInfo(userInfo);
        });
    }
  }

  /**
   * 获取当前 token
   * @returns {string} token 字符串,未登录返回空串
   */
  getToken(): string | null {
    return this.auth?.token ?? null;
  }

  /**
   * 获取当前用户信息
   * @returns {User} 用户信息,未登录返回空对象
   */
  getUserInfo(): User {
    return this.userInfo;
  }

  /**
   * 获取当前用户 ID
   * @returns {number | null} 用户 ID,未登录返回 null
   */
  getUserId(): number | null {
    return this.userInfo?.id ?? null;
  }

  /**
   * 当前是否已登录(依据 auth 与 userInfo 是否存在)
   * @returns {boolean} 登录状态
   */
  isLoggedIn(): boolean {
    return !!this.getToken();
  }

  /**
   * 是否拥有未过期的访问令牌
   * @returns {boolean} 是否可用
   */
  hasValidToken(): boolean {
    return !!this.auth?.token && !this.auth.isExpired();
  }

  /**
   * 获取刷新 token
   * @returns {string | null} 刷新 token
   */
  getRefreshToken(): string | null {
    return this.auth?.refreshToken ?? null;
  }

  /**
   * 持久化当前用户状态
   * @returns {void} 无返回值
   */
  private persist(): void {
    PersistenceV2.save(USER_STATE_KEY);
  }
}

/**
 * @file Token 本地存储数据源实现,基于 Preferences 封装
 * @author Joker.X
 */
export class TokenStore {
  /**
   * Preferences 工具实例
   */
  private prefs: PreferencesUtil;
  /**
   * Preferences 文件名,用于存储 Token
   */
  private static readonly PREFS_NAME: string = "token_store";
  /**
   * Token 键名
   */
  private static readonly KEY_TOKEN: string = "token";

  /**
   * 构造函数
   */
  constructor() {
    this.prefs = new PreferencesUtil(ContextUtil.getUIAbilityCtx(), TokenStore.PREFS_NAME);
  }

  /**
   * 保存 Token
   * @param {string} token Token
   * @returns {Promise<void>} Promise<void>
   */
  async saveToken(token: string): Promise<void> {
    await this.prefs.set(TokenStore.KEY_TOKEN, token);
  }

  /**
   * 读取 Token(默认返回空字符串)
   * @returns {Promise<string>} Token
   */
  async getToken(): Promise<string> {
    const value: preferences.ValueType = await this.prefs.get(TokenStore.KEY_TOKEN, "");
    return typeof value === "string" ? value : "";
  }

  /**
   * 清除 Token
   * @returns {Promise<void>} Promise<void>
   */
  async clearToken(): Promise<void> {
    await this.prefs.remove(TokenStore.KEY_TOKEN);
  }
}

/**
 * 获取或创建全局用户状态(持久化)
 * @returns {UserState} 全局用户状态
 * @example
* const state = getUserState();
 */
export function getUserState(): UserState {
  return PersistenceV2.globalConnect<UserState>({
    type: UserState,
    key: USER_STATE_KEY,
    defaultCreator: () => new UserState(),
    areaMode: contextConstant.AreaMode.EL3
  })!;
}

// 接受序列化失败的回调
PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {
  console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
});