"use client";
/**
 * SpAsyncUtil — 键值对持久化工具类（基于 unstorage）
 *
 * 用法：
 *   ```ts
 *   import { SpAsyncUtil } from "@/utils/storage";
 *
 *   const r = await SpAsyncUtil.getString("auth_token");
 *   if (r.success && r.data) { ... }
 *   ```
 */
import { createStorage, type Storage } from "unstorage";
import localStorageDriver from "unstorage/drivers/localstorage";
import memoryDriver from "unstorage/drivers/memory";
import type { ZodType } from "zod";

import { Result, type Result as ResultT } from "@/utils/result";

export class SpAsyncUtil {
  // ===== 私有静态状态 =====
  // 环境判断 + 安全初始化：SSR 用 memory driver，浏览器用 localStorage driver。
  // unstorage 1.10+ 要求显式传入 localStorage，故这里同步注入 window.localStorage。
  private static _storage: Storage = createDefaultStorage();

  // 私有构造函数：禁止实例化（对齐 Dart `SpAsyncUtil._()`）
  private constructor() {}

  // ===== 底层 storage 访问 =====

  /**
   * 替换底层 storage 实例（仅测试/Storybook 用）
   * @internal
   */
  static setStorage(instance: Storage): void {
    SpAsyncUtil._storage = instance;
  }

  /** 获取底层 storage 实例（高级用法） */
  static getRawStorage(): Storage {
    return SpAsyncUtil._storage;
  }

  // ===== string =====
  static async getString(key: string): Promise<ResultT<string | null>> {
    try {
      const value = await SpAsyncUtil._storage.getItem<string>(key);
      if (value === null || value === undefined) return Result.ok(null);
      if (typeof value !== "string") return Result.ok(null);
      if (value.length === 0) return Result.ok(null);
      return Result.ok(value);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async setString(
    key: string,
    value: string,
  ): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.setItem(key, value);
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  // ===== int =====
  static async getInt(key: string): Promise<ResultT<number | null>> {
    try {
      const value = await SpAsyncUtil._storage.getItem<number>(key);
      if (value === null || value === undefined) return Result.ok(null);
      if (typeof value !== "number" || !Number.isFinite(value)) return Result.ok(null);
      return Result.ok(Math.trunc(value));
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async setInt(key: string, value: number): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.setItem(key, value);
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  // ===== double =====
  static async getDouble(key: string): Promise<ResultT<number | null>> {
    try {
      const value = await SpAsyncUtil._storage.getItem<number>(key);
      if (value === null || value === undefined) return Result.ok(null);
      if (typeof value !== "number" || !Number.isFinite(value)) return Result.ok(null);
      return Result.ok(value);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async setDouble(key: string, value: number): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.setItem(key, value);
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  // ===== bool =====
  static async getBool(key: string): Promise<ResultT<boolean | null>> {
    try {
      const value = await SpAsyncUtil._storage.getItem<boolean>(key);
      if (value === null || value === undefined) return Result.ok(null);
      if (typeof value !== "boolean") return Result.ok(null);
      return Result.ok(value);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async setBool(key: string, value: boolean): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.setItem(key, value);
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  // ===== string list =====
  static async getStringList(key: string): Promise<ResultT<string[] | null>> {
    try {
      const value = await SpAsyncUtil._storage.getItem<string[]>(key);
      if (value === null || value === undefined) return Result.ok(null);
      if (!Array.isArray(value)) return Result.ok(null);
      if (!value.every((v) => typeof v === "string")) return Result.ok(null);
      return Result.ok(value);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async setStringList(
    key: string,
    value: string[],
  ): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.setItem(key, value);
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  // ===== JSON (with optional Zod validation) =====
  static async getJson<T>(
    key: string,
    schema: ZodType<T>,
  ): Promise<ResultT<T | null>> {
    try {
      const value = await SpAsyncUtil._storage.getItem<unknown>(key);
      if (value === null || value === undefined) return Result.ok(null);
      const json = typeof value === "string" ? JSON.parse(value) : value;
      const parsed = schema.parse(json);
      return Result.ok(parsed);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async setJson<T>(
    key: string,
    value: T,
    schema?: ZodType<T>,
  ): Promise<ResultT<void>> {
    try {
      const validated = schema ? schema.parse(value) : value;
      await SpAsyncUtil._storage.setItem(key, JSON.stringify(validated));
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  // ===== generic operations =====
  static async remove(key: string): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.removeItem(key);
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async clear(): Promise<ResultT<void>> {
    try {
      await SpAsyncUtil._storage.clear();
      return Result.ok(undefined);
    } catch (e) {
      return Result.err(toError(e));
    }
  }

  static async has(key: string): Promise<ResultT<boolean>> {
    try {
      const exists = await SpAsyncUtil._storage.hasItem(key);
      return Result.ok(exists);
    } catch (e) {
      return Result.err(toError(e));
    }
  }
}

// ============================================================
// 内部辅助
// ============================================================
function toError(e: unknown): Error {
  return e instanceof Error ? e : new Error(String(e));
}

function createDefaultStorage(): Storage {
  if (typeof window === "undefined") {
    return createStorage({ driver: memoryDriver() });
  }

  try {
    return createStorage({
      driver: localStorageDriver({
        base: "cozsweet:",
        localStorage: window.localStorage,
        window,
      }),
    });
  } catch {
    return createStorage({ driver: memoryDriver() });
  }
}
