"use client";

/**
 * AuthStorage 完整实现（基于 unstorage 抽象）
 *
 * SECURITY: 当前与 Dart 端行为一致，refresh_token 以明文存于 localStorage。
 * 后续轮次将升级到 HttpOnly Cookie 方案，参见 `clearAuthData` 处的 TODO 标记。
 *
 * 设计说明：
 *   - 内部使用 `SpAsyncUtil` 静态类（@/utils/storage）
 *   - 浏览器 → `localStorage` driver；SSR → memory driver（unstorage 自动）
 *   - 单例挂在 class 静态字段，规避 HMR 复用污染
 *   - `hasXxx` = `token != null && token.length > 0`，对齐 Dart 端 `isNotEmpty` 语义
 *   - `clearAuthData` 顺序清理：loginToken → loginProvider → guestToken → refreshToken，任一失败立即返回
 */

import { LoginStatus, type LoginStatus as LoginStatusT } from "@/data/dto/auth";
import { Result, type Result as ResultT, SpAsyncUtil } from "@/utils";
import { StorageKeys } from "../storage_keys";
import type { IAuthStorage } from "./iauth_storage";

export class AuthStorage implements IAuthStorage {
  private static _instance: AuthStorage | null = null;

  static getInstance(): AuthStorage {
    if (!AuthStorage._instance) AuthStorage._instance = new AuthStorage();
    return AuthStorage._instance;
  }

  /** @internal */
  static _resetForTests(): void {
    AuthStorage._instance = null;
  }

  // ---- login token ----

  getLoginToken(): Promise<ResultT<string | null>> {
    return SpAsyncUtil.getString(StorageKeys.loginToken);
  }
  setLoginToken(token: string): Promise<ResultT<void>> {
    return SpAsyncUtil.setString(StorageKeys.loginToken, token);
  }
  async hasLoginToken(): Promise<ResultT<boolean>> {
    const r = await this.getLoginToken();
    if (!r.success) return Result.err(r.error);
    return Result.ok(r.data !== null && r.data.length > 0);
  }
  clearLoginToken(): Promise<ResultT<void>> {
    return SpAsyncUtil.remove(StorageKeys.loginToken);
  }

  // ---- login provider ----

  async getLoginProvider(): Promise<ResultT<LoginStatusT | null>> {
    const r = await SpAsyncUtil.getString(StorageKeys.loginProvider);
    if (!r.success) return Result.err(r.error);
    if (r.data === null || r.data.length === 0) return Result.ok(null);
    if (isLoginStatus(r.data)) return Result.ok(r.data);
    return Result.ok(null);
  }
  setLoginProvider(provider: LoginStatusT): Promise<ResultT<void>> {
    return SpAsyncUtil.setString(StorageKeys.loginProvider, provider);
  }
  clearLoginProvider(): Promise<ResultT<void>> {
    return SpAsyncUtil.remove(StorageKeys.loginProvider);
  }

  // ---- guest token ----

  getGuestToken(): Promise<ResultT<string | null>> {
    return SpAsyncUtil.getString(StorageKeys.guestToken);
  }
  setGuestToken(token: string): Promise<ResultT<void>> {
    return SpAsyncUtil.setString(StorageKeys.guestToken, token);
  }
  async hasGuestToken(): Promise<ResultT<boolean>> {
    const r = await this.getGuestToken();
    if (!r.success) return Result.err(r.error);
    return Result.ok(r.data !== null && r.data.length > 0);
  }
  clearGuestToken(): Promise<ResultT<void>> {
    return SpAsyncUtil.remove(StorageKeys.guestToken);
  }

  // ---- device id ----

  getDeviceId(): Promise<ResultT<string | null>> {
    return SpAsyncUtil.getString(StorageKeys.deviceId);
  }
  setDeviceId(deviceId: string): Promise<ResultT<void>> {
    return SpAsyncUtil.setString(StorageKeys.deviceId, deviceId);
  }

  // ---- refresh token ----
  
  getRefreshToken(): Promise<ResultT<string | null>> {
    return SpAsyncUtil.getString(StorageKeys.refreshToken);
  }
  setRefreshToken(token: string): Promise<ResultT<void>> {
    return SpAsyncUtil.setString(StorageKeys.refreshToken, token);
  }
  clearRefreshToken(): Promise<ResultT<void>> {
    return SpAsyncUtil.remove(StorageKeys.refreshToken);
  }

  // ---- facebook id ----

  getFacebookId(): Promise<ResultT<string | null>> {
    return SpAsyncUtil.getString(StorageKeys.facebookId);
  }
  setFacebookId(id: string): Promise<ResultT<void>> {
    return SpAsyncUtil.setString(StorageKeys.facebookId, id);
  }
  clearFacebookId(): Promise<ResultT<void>> {
    return SpAsyncUtil.remove(StorageKeys.facebookId);
  }

  // ---- bulk clear ----

  async clearAuthData(): Promise<ResultT<void>> {
    const r1 = await this.clearLoginToken();
    if (!r1.success) return r1;
    const r2 = await this.clearLoginProvider();
    if (!r2.success) return r2;
    const r3 = await this.clearGuestToken();
    if (!r3.success) return r3;
    const r4 = await this.clearRefreshToken();
    if (!r4.success) return r4;
    return this.clearFacebookId();
  }
}

function isLoginStatus(value: string): value is LoginStatusT {
  return Object.values(LoginStatus).includes(value as LoginStatusT);
}
