import type {
  LatexCompilerCapabilities,
  LatexCompilerEngineCapability,
} from '@learnitive/latex-compiler';
import type { LearnitiveCompiler } from '@learnitive/project-storage';

const STATUS_URL = '/compiler/status.json';
const ENGINES: readonly LearnitiveCompiler[] = ['pdflatex', 'xelatex', 'lualatex'];

function validEngineCapability(value: unknown): value is LatexCompilerEngineCapability {
  if (!value || typeof value !== 'object') return false;
  const candidate = value as Partial<LatexCompilerEngineCapability>;
  return (
    typeof candidate.available === 'boolean' &&
    (candidate.preferredBackend == null ||
      candidate.preferredBackend === 'busytex' ||
      candidate.preferredBackend === 'swiftlatex') &&
    (candidate.reason == null || typeof candidate.reason === 'string') &&
    (candidate.supportsSyncTeX == null || typeof candidate.supportsSyncTeX === 'boolean') &&
    (candidate.supportsBiber == null || typeof candidate.supportsBiber === 'boolean') &&
    (candidate.syncTeXBackend == null ||
      candidate.syncTeXBackend === 'busytex' ||
      candidate.syncTeXBackend === 'swiftlatex')
  );
}


function validStringArray(value: unknown): value is readonly string[] {
  return Array.isArray(value) && value.every((item) => typeof item === 'string');
}

function validRuntimeAssets(value: unknown): boolean {
  if (value == null) return true;
  if (!value || typeof value !== 'object') return false;
  const busytex = (value as { busytex?: unknown }).busytex;
  if (busytex == null) return true;
  if (!busytex || typeof busytex !== 'object') return false;
  const candidate = busytex as {
    version?: unknown;
    fingerprint?: unknown;
    moduleUrl?: unknown;
    basePath?: unknown;
    requiredFiles?: unknown;
    engineRequiredFiles?: unknown;
  };
  if (
    !(candidate.version == null || typeof candidate.version === 'string') ||
    !(candidate.fingerprint == null || typeof candidate.fingerprint === 'string') ||
    typeof candidate.moduleUrl !== 'string' ||
    typeof candidate.basePath !== 'string' ||
    !validStringArray(candidate.requiredFiles) ||
    !candidate.engineRequiredFiles ||
    typeof candidate.engineRequiredFiles !== 'object'
  ) {
    return false;
  }
  const engineFiles = candidate.engineRequiredFiles as Record<string, unknown>;
  return ENGINES.every(
    (engine) => engineFiles[engine] == null || validStringArray(engineFiles[engine]),
  );
}

function validCapabilities(value: unknown): value is LatexCompilerCapabilities {
  if (!value || typeof value !== 'object') return false;
  const candidate = value as Partial<LatexCompilerCapabilities>;
  if (
    candidate.schemaVersion !== 1 ||
    !candidate.engines ||
    !candidate.texlive ||
    !validRuntimeAssets(candidate.runtimeAssets)
  ) {
    return false;
  }
  return ENGINES.every((engine) => validEngineCapability(candidate.engines?.[engine]));
}

export function fallbackCompilerCapabilities(): LatexCompilerCapabilities {
  return {
    schemaVersion: 1,
    mode: 'swiftlatex-pdflatex',
    engines: {
      pdflatex: {
        available: true,
        preferredBackend: 'swiftlatex',
        reason: null,
        supportsSyncTeX: false,
        syncTeXBackend: null,
        supportsBiber: false,
      },
      xelatex: {
        available: false,
        preferredBackend: null,
        reason: 'XeLaTeX requires the full BusyTeX compiler profile.',
        supportsSyncTeX: false,
        syncTeXBackend: null,
        supportsBiber: false,
      },
      lualatex: {
        available: false,
        preferredBackend: null,
        reason: 'LuaLaTeX requires the full BusyTeX compiler profile.',
        supportsSyncTeX: false,
        syncTeXBackend: null,
        supportsBiber: false,
      },
    },
    texlive: {
      bundled: {
        available: false,
        bundleId: null,
        compatibility: null,
        fileCount: 0,
        textFileCount: 0,
        binaryFileCount: 0,
      },
      staticMirror: {
        enabled: true,
        endpoint: 'https://cdn.jsdelivr.net/gh/SachaNevsky/latexdiff-texmf-dist@aca46fc00975feebf98e038976790805c3e932df',
        index: '/texlive/texlive-lsr.txt',
      },
      remote: {
        enabled: false,
        endpoint: null,
        configurable: true,
      },
      fullCoverage: {
        available: false,
        strategy: 'local-bundles-only',
        localBundles: [],
        endpoint: null,
        remoteFonts: false,
      },
      busytexEndpoint: null,
    },
  };
}

export async function loadCompilerDeploymentStatus(
  signal?: AbortSignal,
): Promise<LatexCompilerCapabilities> {
  try {
    const response = await fetch(STATUS_URL, {
      cache: 'no-store',
      signal,
      headers: { accept: 'application/json' },
    });
    if (!response.ok) return fallbackCompilerCapabilities();
    const payload: unknown = await response.json();
    return validCapabilities(payload) ? payload : fallbackCompilerCapabilities();
  } catch {
    signal?.throwIfAborted();
    return fallbackCompilerCapabilities();
  }
}
