<script setup>
import { computed, onMounted, ref, watch } from "vue";
import { Effect, Option } from "effect";
import { Fetch } from "fx-fetch";
import { useIntervalFn, useWindowFocus } from "@vueuse/core";
import NumberFlow from "@number-flow/vue";
import { cel } from "../../../../../utils/cel";
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
import { fetchJsonOption } from "../../../../../share/request";
defineOptions({ name: "ShwfedBlockAnimatedNumberItem" });
const props = defineProps({
  item: { type: null, required: true }
});
const inheritedContext = injectCELContext();
const json = ref(void 0);
const numberValue = ref(0);
function baseContext() {
  return celBindings(inheritedContext);
}
function toFiniteNumber(v) {
  if (typeof v === "number" && Number.isFinite(v)) return v;
  if (typeof v === "string" && v.trim() !== "") {
    const n = Number(v);
    return Number.isFinite(n) ? n : 0;
  }
  return 0;
}
const jsonOption = computed(
  () => json.value === void 0 ? Option.none() : Option.some(json.value)
);
function evalString(expression) {
  if (!expression) return "";
  try {
    const r = Effect.runSync(cel(expression, { ...baseContext(), json: jsonOption.value }));
    return r === null || r === void 0 ? "" : String(r);
  } catch {
    return "";
  }
}
const prefixText = computed(() => evalString(props.item.prefix));
const suffixText = computed(() => evalString(props.item.suffix));
function evalStyle(expression) {
  if (!expression) return void 0;
  try {
    const r = Effect.runSync(cel(expression, { ...baseContext(), json: jsonOption.value }));
    if (r === null || r === void 0) return void 0;
    if (typeof r === "string") return r;
    if (typeof r === "object") return r;
    return String(r);
  } catch {
    return void 0;
  }
}
const styleValue = computed(() => evalStyle(props.item.style));
async function refresh() {
  const ds = props.item.dataSource;
  const ctx = baseContext();
  const program = Effect.gen(function* () {
    let jsonOpt = Option.none();
    if (ds.request) {
      jsonOpt = yield* fetchJsonOption(yield* cel(ds.request, ctx));
    }
    const value = yield* cel(ds.value, { ...ctx, json: jsonOpt });
    return { json: Option.getOrUndefined(jsonOpt), value };
  });
  try {
    const result = await Effect.runPromise(Effect.provide(program, Fetch.layer));
    json.value = result.json;
    numberValue.value = toFiniteNumber(result.value);
  } catch (e) {
    console.warn("[shwfed-animated-number] fetch failed", e);
  }
}
const pollingEnabled = computed(() => (props.item.pollingInterval ?? 0) > 0);
const intervalMs = computed(() => Math.max(1, props.item.pollingInterval ?? 1) * 1e3);
const focused = useWindowFocus();
const { pause, resume } = useIntervalFn(() => void refresh(), intervalMs, { immediate: false });
onMounted(() => {
  void refresh();
  if (pollingEnabled.value && focused.value) resume();
});
watch(focused, (isFocused) => {
  if (!pollingEnabled.value) return;
  if (isFocused) {
    void refresh();
    resume();
  } else {
    pause();
  }
});
watch(
  () => [
    props.item.dataSource.request ?? "",
    props.item.dataSource.value,
    props.item.pollingInterval ?? 0
  ].join("|"),
  () => {
    void refresh();
    if (pollingEnabled.value && focused.value) resume();
    else pause();
  }
);
</script>

<template>
  <NumberFlow
    :value="numberValue"
    :prefix="prefixText"
    :suffix="suffixText"
    :style="styleValue"
  />
</template>
