/**
 * 仓库层统一 Result<T>
 *
 * 与 `src/data/storage/result.ts` 的 `Result<T>`（`{kind, value}` 形态）并存：
 *   - 本类型供仓库层（`src/data/repositories/*`）使用，`{success, data}` 形态更贴近
 *     原 Dart `Result.success` / `Result.failure` 命名与 API 端 envelope 风格。
 *   - 存储层继续使用 `{kind, value}`，因为它的消费者（localStorage、Dexie）已经在
 *     大量代码中 pattern-match `r.kind`。
 *   - 两个类型路径不同（`@/data/result` vs `@/data/storage/result`），不冲突；
 *     如需在同模块中混用，可用 `import { Result as StorageResult } from
 *     "@/data/storage/result"` 别名。
 *
 * `error` 固定为 `Error`（非 `unknown`）：HTTP 拦截器与共享 unwrap 都抛 `ApiError`
 * （`ApiError extends Error`），仓库 `Result.wrap` 捕获后用 `toError` 规范化，
 * 调用方能可靠地 `instanceof ApiError` / `error.message` 访问错误信息。
 */
import { Logger } from "./logger";

export type Result<T> =
  | { readonly success: true; readonly data: T }
  | { readonly success: false; readonly error: Error };

/** 仓库层 Result.wrap 专用 logger —— 自动带 component: "Result" 标签 */
const log = new Logger("Result");

export const Result = {
  /** 构造成功结果。 */
  ok<T>(data: T): Result<T> {
    return { success: true, data };
  },

  /**
   * 构造失败结果。`error` 接受任意 thrown 值，内部用 `toError` 归一化为 `Error`。
   */
  err<T = never>(error: unknown): Result<T> {
    return { success: false, error: toError(error) };
  },

  /** 类型守卫：true 分支。 */
  isOk<T>(r: Result<T>): r is { readonly success: true; readonly data: T } {
    return r.success;
  },

  /** 类型守卫：false 分支。 */
  isErr<T>(r: Result<T>): r is { readonly success: false; readonly error: Error } {
    return !r.success;
  },

  /** 不可变的链式 map：失败时原样传递。 */
  map<T, U>(r: Result<T>, fn: (v: T) => U): Result<U> {
    return r.success ? Result.ok(fn(r.data)) : r;
  },

  /**
   * 捕获异步 thunk 的异常并包装成 `Result<T>`。仓库内主要用这个把
   * `*Api` 调用从「throw 风格」桥接到「Result 风格」。
   *
   * 错误处理策略（重点）：
   *   1. 捕获后用 `toError` 规范化（保留 .stack / .code / .status 等字段）
   *   2. 用 Logger 记录（带 stack + component=Result 标签）—— 调试 dev 控制台可见，
   *      生产环境走 JSON pipeline 接入日志平台
   *   3. 不重新抛出 —— 调用方拿到的永远是 `Result<T>`（throw 风格调用方可在
   *      最外层显式 `throw Result.unwrap(r)`）
   */
  async wrap<T>(thunk: () => Promise<T>): Promise<Result<T>> {
    try {
      return Result.ok(await thunk());
    } catch (e) {
      const err = toError(e);
      log.error(
        { err, stack: err.stack, type: err.constructor.name },
        "Result.wrap caught exception",
      );
      return Result.err(err);
    }
  },
} as const;

/**
 * 把任意 thrown 值规范化为 `Error`：
 *   - 已是 `Error` 子类 → 原样返回（保留 `.code` / `.status` 等自定义字段）
 *   - string → `new Error(str)`
 *   - 其他 → `new Error(JSON.stringify(value))`，失败则 `new Error(String(value))`
 */
export function toError(value: unknown): Error {
  if (value instanceof Error) return value;
  if (typeof value === "string") return new Error(value);
  try {
    return new Error(JSON.stringify(value));
  } catch {
    return new Error(String(value));
  }
}
