import { computed, inject, Injectable, resource, Signal } from '@angular/core';
import { DBHOrderItemListItemDTO } from '@generated/swagger/oms-api';
import { logger } from '@isa/core/logging';
import { OpenRewardTasksService } from '../services/open-reward-tasks.service';
import { OMS_OPEN_REWARD_TASK_REFRESH_INTERVAL_MS } from '../constants';

/**
 * Global resource for managing open reward distribution tasks (Prämienausgabe).
 *
 * Provides reactive access to unfinished reward orders across the application.
 * This resource is provided at root level to ensure a single shared instance
 * for both the side menu indicator and the reward catalog carousel.
 *
 * @example
 * ```typescript
 * // In component
 * readonly openTasksResource = inject(OpenRewardTasksResource);
 * readonly hasOpenTasks = computed(() =>
 *   (this.openTasksResource.tasks()?.length ?? 0) > 0
 * );
 * ```
 */
@Injectable({ providedIn: 'root' })
export class OpenRewardTasksResource {
  #logger = logger({ resource: 'OpenRewardTasksResource' });

  /**
   * Interval ID for auto-refresh timer. Null when not actively polling.
   */
  #interval: ReturnType<typeof setInterval> | null = null;

  /**
   * Reference counter tracking how many consumers have started auto-refresh.
   * Used to prevent stopping the interval while other consumers still need it.
   */
  #refCount = 0;

  #openRewardTasksService = inject(OpenRewardTasksService);

  /**
   * Internal resource that manages data fetching and caching
   */
  #resource = resource({
    loader: async ({ abortSignal }): Promise<DBHOrderItemListItemDTO[]> => {
      return await this.#openRewardTasksService.getOpenRewardTasks(abortSignal);
    },
    defaultValue: [],
  });

  /**
   * Signal containing the array of open reward tasks.
   * Returns empty array when loading or on error.
   */
  readonly tasks: Signal<readonly DBHOrderItemListItemDTO[]> =
    this.#resource.value.asReadonly();

  /**
   * Signal indicating whether data is currently being fetched
   */
  readonly loading: Signal<boolean> = this.#resource.isLoading;

  /**
   * Signal containing error message if fetch failed, otherwise null
   */
  readonly error = computed(() => this.#resource.error()?.message ?? null);

  /**
   * Signal indicating whether there are any open tasks
   */
  readonly hasOpenTasks = computed(() => (this.tasks()?.length ?? 0) > 0);

  /**
   * Signal containing the count of open tasks
   */
  readonly taskCount = computed(() => this.tasks()?.length ?? 0);

  /**
   * Manually refresh the open tasks data.
   * Useful for updating after a task is completed.
   */
  refresh(): void {
    this.#resource.reload();
  }

  /**
   * Starts automatic polling of open reward tasks.
   * Refreshes data every 5 minutes to keep the task list up-to-date.
   * Uses reference counting - multiple consumers can safely call this method.
   * The interval only starts when the first consumer calls it.
   */
  startAutoRefresh(): void {
    this.#refCount++;

    this.#logger.debug('Auto-refresh start requested', () => ({
      refCount: this.#refCount,
      intervalActive: this.#interval !== null,
    }));

    if (this.#interval) {
      return; // Already running
    }

    this.#interval = setInterval(() => {
      this.refresh();
    }, OMS_OPEN_REWARD_TASK_REFRESH_INTERVAL_MS);

    this.#logger.info('Auto-refresh started', () => ({
      intervalMs: OMS_OPEN_REWARD_TASK_REFRESH_INTERVAL_MS,
      refCount: this.#refCount,
    }));
  }

  /**
   * Stops automatic polling of open reward tasks.
   * Uses reference counting - only actually stops when all consumers have called this.
   * Should be called during component cleanup to prevent memory leaks.
   */
  stopAutoRefresh(): void {
    if (this.#refCount > 0) {
      this.#refCount--;
    }

    this.#logger.debug('Auto-refresh stop requested', () => ({
      refCount: this.#refCount,
      intervalActive: this.#interval !== null,
    }));

    if (this.#refCount === 0 && this.#interval) {
      clearInterval(this.#interval);
      this.#interval = null;

      this.#logger.info('Auto-refresh stopped', () => ({
        reason: 'All consumers released',
      }));
    }
  }
}
