/**
 * @file process.ts - API wrapper for IWS5 process objects and functions.
 */

import { assembleQueryParams, FetchError } from '../utils/fetchHelper.ts';
import { getAccessToken } from '../services/authService.ts';
import { StatusCodes } from 'http-status-codes';
import type { DocumentTemplate } from './documentTemplate.ts';
import type { AtAllowRight } from '../types/atAllowRights.ts';

/** Base URL for the IWS5 processes API endpoint */
export const PROCESSES_API_URL =
  window.__APP_CONFIG__?.IWS5_API_URL + '/api/Process';

/**
 * Represents a workflow process definition in the Process Director system.
 * Processes are versioned and contain queues, templates, and permission configurations.
 */
export type Process = {
  /** Unique identifier of the process */
  id: number;

  /** Display name of the process */
  name: string;

  /** Version string of the process definition (e.g., "1") */
  version: string;
};

/**
 * Retrieves the list of processes.
 *
 * @param latestVersion If true, only the latest version of each process is returned
 * @returns List of processes
 * @throws FetchError If response is not 200-class
 */
export async function listProcesses(
  latestVersion: boolean = false
): Promise<Process[]> {
  const _url = assembleQueryParams(PROCESSES_API_URL + '/list', {
    latestVersion,
  });

  // Attempt GET /api/Process/list
  try {
    const response = await fetch(_url.toString(), {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${getAccessToken()}`,
      },
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to retrieve processes',
        response
      );
    }
    if (response.status === StatusCodes.NO_CONTENT) {
      return [] as Process[];
    }

    return (await response.json()).responseModel as Process[];
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

/**
 * Retrieve the current user's permissions for a given process.
 *
 * @param processId ID of process to retrieve permissions for
 * @returns List of permissions
 * @throws FetchError If response is not 200-class
 */
export async function getProcessPermissions(
  processId: number
): Promise<AtAllowRight[]> {
  const _url = PROCESSES_API_URL + '/' + processId + '/permissions';

  // Attempt GET /api/Process/{processId}/permissions
  try {
    const response = await fetch(_url.toString(), {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${getAccessToken()}`,
      },
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to retrieve process permissions',
        response
      );
    }

    return (await response.json()).responseModel as AtAllowRight[];
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}

/**
 * Retrieves the allowed document templates for a specific process.
 *
 * @param processId ID of process to retrieve allowed document templates for
 * @returns List of document templates
 * @throws FetchError If response is not 200-class
 */
export async function listAllowedTemplates(
  processId: number
): Promise<DocumentTemplate[]> {
  const _url = PROCESSES_API_URL + '/' + processId + '/allowed-templates';

  // Attempt GET /api/Process/{processId}/allowed-templates
  try {
    const response = await fetch(_url.toString(), {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${getAccessToken()}`,
      },
    });
    if (!response.ok) {
      const errorText = await response.text();
      throw new FetchError(
        errorText || 'Failed to retrieve allowed templates',
        response
      );
    }
    if (response.status === StatusCodes.NO_CONTENT) {
      return [] as DocumentTemplate[];
    }

    return (await response.json()).responseModel
      .templates as DocumentTemplate[];
  } catch (error) {
    throw new FetchError((error as Error).message);
  }
}
