import type { Diagnostic, FormulaStatus } from '#/api/x/eln/formulas';

export type FormulaVersionAction = 'cancel' | 'copy' | 'edit' | 'preRelease' | 'preview' | 'publish' | 'setCurrent';

const FORMULA_VERSION_ACTION_ORDER: FormulaVersionAction[] = ['preview', 'edit', 'preRelease', 'publish', 'cancel', 'setCurrent', 'copy'];

export interface EditorDiagnostic {
  code?: string;
  from: number;
  message?: string;
  severity: Diagnostic['severity'];
  to: number;
}

export function formulaVersionActions(input: { current: boolean; enabled?: boolean; status: FormulaStatus }): FormulaVersionAction[] {
  const available = new Set<FormulaVersionAction>();
  if (input.status === 'PRE_RELEASE' || input.status === 'PUBLISHED') available.add('preview');
  if (input.enabled === false) {
    if (input.status === 'DRAFT' || input.status === 'PRE_RELEASE') available.add('cancel');
  } else
    switch (input.status) {
      case 'DRAFT': {
        available.add('edit').add('preRelease').add('cancel');

        break;
      }
      case 'PRE_RELEASE': {
        available.add('publish').add('cancel').add('copy');

        break;
      }
      case 'PUBLISHED': {
        if (!input.current) available.add('setCurrent');
        available.add('copy');

        break;
      }
      // No default
    }
  return FORMULA_VERSION_ACTION_ORDER.filter((action) => available.has(action));
}

export function acceptValidationResponse(input: { received: number; sent: number }): boolean {
  return input.received === input.sent;
}

export function toEditorDiagnostics(diagnostics: Diagnostic[], documentLength = Number.MAX_SAFE_INTEGER): EditorDiagnostic[] {
  const maximumOffset = Math.max(0, toInteger(documentLength));
  return diagnostics.map((diagnostic) => {
    const from = clampOffset(diagnostic.start, maximumOffset);
    const to = Math.max(from, clampOffset(diagnostic.end, maximumOffset));
    return {
      code: diagnostic.code,
      from,
      message: diagnostic.message,
      severity: diagnostic.severity,
      to,
    };
  });
}

function clampOffset(value: number, maximum: number): number {
  return Math.min(maximum, Math.max(0, toInteger(value)));
}

function toInteger(value: number): number {
  return Number.isFinite(value) ? Math.trunc(value) : 0;
}
