import type { App } from "@riwa/api-types";
import type { WatchSource } from "vue";
import { treaty } from "@elysiajs/eden";
import { toastController } from "@ionic/vue";
import { i18n } from "@/locales";
import { useMocks } from "@/mocks";

const baseURL = import.meta.env.DEV ? window.location.origin : import.meta.env.VITE_API_URL;

const client = treaty<App>(baseURL, {
  fetch: {
    credentials: "include",
  },
  headers() {
    const token = localStorage.getItem("user-token") || "";
    const headers = new Headers();
    headers.append("Content-Type", "application/json");
    headers.append("Authorization", token ? `Bearer ${token}` : "");
    return headers;
  },
});

export interface SafeClientOptions {
  silent?: boolean;
  immediate?: boolean;
  watchSource?: WatchSource; // 用于监听的响应式数据源
}

export interface SafeClientReturn<T, E> {
  data: Ref<T | null>;
  error: Ref<E | null>;
  isPending: Ref<boolean>;
  execute: () => Promise<void>;
  onFetchResponse: (callback: (data: T, error: E) => void) => void;
  stopWatching?: () => void;
}

export type RequestPromise<T, E> = Promise<{ data: T; error: E; status?: number; response?: Response }>;

export function safeClient<T, E>(
  requestPromise: (() => RequestPromise<T, E>) | RequestPromise<T, E>,
  options: SafeClientOptions = {},
): SafeClientReturn<T, E> & Promise<SafeClientReturn<T, E>> {
  const { immediate = true, watchSource } = options;
  const data = ref<T | null>(null);
  const error = ref<E | null>(null);
  const isPending = ref(false);
  let responseCallback: ((data: T, error: E) => void) | null = null;
  let stopWatcher: (() => void) | undefined;

  const execute = async () => {
    isPending.value = true;
    let request: () => RequestPromise<T, E>;
    if (typeof requestPromise !== "function") {
      request = () => Promise.resolve(requestPromise);
    }
    else {
      request = requestPromise;
    }

    const res = await request().finally(() => {
      isPending.value = false;
    });

    if (res.error && res.status === 418) {
      if (!options.silent) {
        const toast = await toastController.create({
          message: i18n.global.t((res.error as any).value.code, {
            ...(res.error as any).value.context,
          }),
          duration: 3000,
          position: "bottom",
          color: "danger",
        });
        await toast.present();
      }

      throw res.error;
    }
    data.value = res.data;
    error.value = res.error;

    // 调用注册的回调函数
    if (responseCallback) {
      responseCallback(res.data, res.error);
    }
  };

  function onFetchResponse(callback: (data: T, error: E) => void) {
    responseCallback = callback;
  }

  function stopWatching() {
    if (stopWatcher) {
      stopWatcher();
      stopWatcher = undefined;
    }
  }

  // 如果提供了 watchSource，则监听其变化
  if (watchSource) {
    stopWatcher = watch(
      watchSource,
      () => {
        execute();
      },
      { immediate: false }, // 不立即执行，避免与 immediate 选项冲突
    );
  }

  const result: SafeClientReturn<T, E> = {
    data: data as Ref<T | null>,
    error: error as Ref<E | null>,
    isPending,
    execute,
    onFetchResponse,
    stopWatching,
  };

  const promise = immediate ? execute().then(() => result) : Promise.resolve(result);

  Object.assign(promise, result);

  return promise as SafeClientReturn<T, E> & Promise<SafeClientReturn<T, E>>;
}

export function mockClient<T = any, E = any>(key: string): SafeClientReturn<T, E> & Promise<SafeClientReturn<T, E>> {
  const requestPromise = async () => {
    const mocks = useMocks();
    const mockFn = mocks.get(key);
    if (!mockFn) {
      throw new Error(`Mock with key "${key}" not found.`);
    }
    const data = await mockFn();
    return { data: data as T, error: null as E };
  };
  return safeClient<T, E>(requestPromise, { immediate: true });
}

export { client };
