import { Meta } from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/en/functional/Functions/executeUse - Singleton with lifecycle management'/>

# `executeUse`

`executeUse` is a factory that wraps any initializer function and turns its result into a **managed singleton**. The object is created exactly once, frozen (`Object.freeze`), and reused on every subsequent call. Depending on the selected type, the singleton can be component-scoped, global, or local.

To ensure unique identifiers, a combination of an internal global code and the `getElementId()` function is used, guaranteeing no collisions even when used across different modules.



### Generic Constraints

- `R` — the type of object returned by the initializer function (`callback`).
- `O extends any[]` — the types of arguments accepted by `callback`.
- `RI extends ExecuteUseReturn<R>` — the resulting singleton type, including management methods.

```typescript
function executeUse<R, O extends any[], RI extends ExecuteUseReturn<R>>(
  callback: (...args: O) => R,
  type: ExecuteUseType = ExecuteUseType.provide
): (...args: O) => RI

function executeUseGlobal<R>(callback: () => R): () => ExecuteUseReturn<R>
function executeUseProvide<R, O extends any[]>(callback: (...args: O) => R): (...args: O) => ExecuteUseReturn<R>
function executeUseLocal<R, O extends any[]>(callback: (...args: O) => R): (...args: O) => ExecuteUseReturn<R>
```

**Parameters:**
- `callback: (...args: O) => R` — The initializer function. Called on the first access and returns an object that will be frozen and cached. Arguments are passed only on the first call.
- `type: ExecuteUseType` — The type of singleton (default: `ExecuteUseType.provide`).

**Returns:** `ExecuteUseReturn<R>` — a frozen object extending `R` with the following methods:
- `init(): Readonly<R>` — returns the raw result of `callback` without any management methods (`init`, `destroyExecute`).
- `destroyExecute?(): void` — only on `local` and `global`. Resets the cache, allowing the object to be re-created on the next call.

### The Initializer Function (`callback`) and its Arguments (`...args: O`)

The main feature of `executeUse` is that the factory function (`callback`) and the arguments passed to it (`...args`) are used **only once** — during actual initialization (the very first call).

- **`callback`**: This is a factory describing the state creation logic. Inside it, you typically declare reactive variables (`ref`, `reactive`), functions to mutate them, and computed values (`computed`). The object returned from `callback` will be "frozen" and cached.
- **`...args: O`**: You can pass any arguments into your initializer (e.g., initial state, ID of the entity being loaded, or an API client). These arguments will be forwarded into the `callback`.

> **Important note about arguments:** Because `executeUse` strictly caches the result of the first call, any arguments passed during **subsequent** calls of the same hook in other components **will be completely ignored**. The object will not be recreated, and the `callback` function will not run again with new arguments (unless you have previously reset the cache via `destroyExecute()`).

### The `init()` Placeholder Method

The `init` method is simply an empty placeholder function that returns the exact same frozen state object. It exists **purely for code readability and Developer Experience (DX)**.

Its main purpose is to give the developer a way to explicitly and visually highlight in the code the exact place where the actual (first) initialization of the singleton takes place. From a technical perspective, `const state = useTheme()` and `const state = useTheme().init()` do exactly the same thing.

```typescript
// Somewhere deep in the component tree, we simply get the readied state
const theme = useTheme()

// And here, in the root component (or main.ts), 
// we explicitly show other developers: "Initialization happens exactly HERE"
const theme = useTheme().init()
```
## Step-by-Step Guide: How to Create and Use Your Own Service

Creating a managed singleton using `executeUse` typically consists of three simple steps.

### Step 1: Defining the State (Factory)
First, decide what type of state you need (`global`, `local`, or `provide`). Create a separate file (e.g., `useMyService.ts`). Use one of the factory functions (e.g., `executeUseGlobal`).

Inside the callback function, define all your reactive variables (`ref`, `reactive`), computed properties (`computed`), and functions to mutate the state:

```typescript
// src/composables/useMyService.ts
import { ref, computed } from 'vue'
import { executeUseGlobal } from '@dxtmisha/functional'

// Create the singleton and encapsulate the logic
const instance = executeUseGlobal(() => {
  // 1. Reactive state
  const count = ref(0)
  
  // 2. Computed properties
  const isPositive = computed(() => count.value > 0)
  
  // 3. Management methods
  const increment = () => count.value++
  const reset = () => { count.value = 0 }

  // Return exactly what should be exposed to the outside
  return { count, isPositive, increment, reset }
})

// Export a wrapper function.
// The () => instance() construct is necessary so that code editors (IDEs)
// correctly recognize useMyService as a composable function.
// This ensures proper autocomplete and type inference.
export const useMyService = () => instance()
```

### Step 2: Initialization (For `global` only)
If you chose the `global` mode (like in the example above), you need to tell the application exactly when to instantiate it. This is usually done once at the entry point (`main.ts`):

```typescript
// src/main.ts
import { createApp } from 'vue'
import { executeUseGlobalInit } from '@dxtmisha/functional'
import App from './App.vue'

// Initialize absolutely all global singletons at once
executeUseGlobalInit() 

createApp(App).mount('#app')
```

> **Note:** If your application uses the `dxtFunctionalPlugin`, you **do not need** to call `executeUseGlobalInit()` manually at startup — the plugin handles it automatically under the hood.

### Step 3: Usage in a Component
Now you can import your `useMyService` function into any Vue component. On the very first logical call, use the `init()` method for clarity.

```vue
<!-- src/components/MyComponent.vue -->
<script setup lang="ts">
import { useMyService } from '@/composables/useMyService'

// We receive the state directly. The init() method indicates
// that the primary (first) access within this scope is happening here.
const { count, isPositive, increment } = useMyService().init()
</script>

<template>
  <div>
    <p>Current count: {{ count }}</p>
    <p>Is positive? {{ isPositive ? 'Yes' : 'No' }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>
```

If for some reason you need to forcefully reset the state (e.g., upon user logout), simply call the built-in reset method:
```typescript
const service = useMyService()
if (service.destroyExecute) {
  service.destroyExecute()
}
```

## The `ExecuteUseType` Enum

### `provide` (component-scoped singleton, default)

This is a component-oriented singleton that is strictly tied to the lifecycle of a Vue component and its entire subtree. Under the hood, it uses Vue's built-in reactivity and context-passing mechanism (`provide`/`inject`), allowing you to safely pass the very same state instance deep down the component tree without having to drill it through props.

**When to use:** 
- For sharing state specifically within a defined component subtree (parent -> multiple nesting levels -> child) without polluting the global store.
- When you need to render multiple independent blocks on the same page (e.g., several complex file uploader widgets), each requiring its own unique state shared only within that widget.
- If you need automatic garbage collection of the data straight from memory when the "owner" component is unmounted.

**How it works:**
The first component that calls this function automatically becomes the "owner". The function instantiates the object and immediately calls `provide(id, instance)`. Any nested components that call the same function will not create a new object; instead, they retrieve the previously created one via `inject(id)`. 
> Note: This type lacks a `destroyExecute()` method because memory is freed automatically by Vue's reactivity system when the owner component is destroyed.

```typescript
import { executeUseProvide } from '@dxtmisha/functional'
import { ref } from 'vue'

const useTheme = executeUseProvide(() => {
  const mode = ref<'light' | 'dark'>('light')
  const toggle = () => { mode.value = mode.value === 'light' ? 'dark' : 'light' }
  return { mode, toggle }
})

// In the parent component (owner) — the object is created and provided:
const theme = useTheme()
theme.toggle()

// In a deeply nested child component — it receives the same object via inject:
const theme = useTheme()

// In a completely different, independent component tree — a NEW instance is created:
const theme2 = useTheme()
```

### `global` (application-wide singleton)

This is a classic Singleton architectural pattern, existing as a strictly unique instance throughout the entire lifetime of your application (from initialization to closing the browser tab). It provides a global point of access to state from literally anywhere in the code.

**When to use:**
- For storing global application state: authentication, current user profile, language settings, global shopping cart.
- When the same data needs to be accessed from completely distinct, unrelated parts of the application (or even outside Vue components, such as in the router).
- As a lightweight replacement for Vuex / Pinia for simple state management tasks.

**How it works:**
The initializer function is **not executed when called**. Instead, it is added to a special internal queue (`globalMethods`). Full initialization of all global objects only occurs upon explicitly calling `executeUseGlobalInit()`, which is typically placed in `main.ts` before the app is mounted. Thereafter, all components receive the same cached object from memory.

```typescript
import { executeUseGlobal, executeUseGlobalInit } from '@dxtmisha/functional'
import { ref } from 'vue'

const useAuth = executeUseGlobal(() => {
  const user = ref<string | null>(null)
  const login = (name: string) => { user.value = name }
  const logout = () => { user.value = null }
  return { user, login, logout }
})

// In main.ts — strictly BEFORE mounting the app (app.mount()):
executeUseGlobalInit()

// In any component, utility, or router:
const auth = useAuth()
auth.login('Alice')

// If you need to forcefully reset the state (recreate the state from scratch):
auth.destroyExecute?.() 
```

### `local` (closure-cached singleton)

This is an independent singleton that relies on the lexical closure mechanism (`closure caching`) in JavaScript. Instead of using the Vue context or the global scope, it preserves the once-generated result directly inside its own function memory, instantly returning it on all subsequent calls.

**When to use:**
- For utilities, factories, or services not coupled to Vue (`provide`/`inject` only function inside a component's `setup`).
- When you need an isolated instance of a heavy class or service only at the exact moment it's actually required (lazy initialization on demand), rather than at app startup.
- For caching the results of heavy mathematical calculations or configuration transformations.

**How it works:**
It does not use Vue mechanisms. On the very first call, the initializer function is executed with the provided arguments. The result is strictly frozen (`Object.freeze`) and stored in a variable inside the `executeUse` closure. On all subsequent calls (even if you pass different arguments), the function instantly returns the already saved object from the variable. 
The `destroyExecute()` method nullifies this internal variable, allowing the initialization algorithm to run again on the next call.

```typescript
import { executeUseLocal } from '@dxtmisha/functional'
import { ref } from 'vue'

const useHeavyConfig = executeUseLocal((env: string) => {
  // Heavy configuration calculation operation...
  const config = ref({ api: `https://${env}.example.com` })
  return { config }
})

// First call — initialization
const devConfig = useHeavyConfig('dev')
console.log(devConfig.config.value.api) // https://dev.example.com

// Second call in another file — returns the same object, the argument is ignored!
const sameConfig = useHeavyConfig('prod') 
console.log(sameConfig.config.value.api) // Still https://dev.example.com

// Forcefully clear the cache
sameConfig.destroyExecute?.()
const newConfig = useHeavyConfig('prod') // Initialization will run again
```

## `executeUseGlobalInit`

```typescript
function executeUseGlobalInit(): void
```

Calls all registered global initializers (`ExecuteUseType.global`) and clears the queue. Calling it again does not re-initialize already created singletons. Should be called **once** at app startup — before mounting the root component.

```typescript
import { createApp } from 'vue'
import { executeUseGlobalInit } from '@dxtmisha/functional'
import App from './App.vue'

executeUseGlobalInit()
createApp(App).mount('#app')
```

