import type {
  ProjectFilePath,
  LearnitiveCompiler,
} from '@learnitive/project-storage';

export type LatexCompilerBackend = 'busytex' | 'swiftlatex' | 'cloud';
export type LatexCompileMode = 'full' | 'fast';
export type LatexDiagnosticSeverity = 'error' | 'warning' | 'info';

export type LatexCompilerEngineCapability = {
  available: boolean;
  preferredBackend: LatexCompilerBackend | null;
  reason: string | null;
  /** True when this deployment can emit a SyncTeX map for this engine. */
  supportsSyncTeX?: boolean;
  /** Backend used when a source map is explicitly required. */
  syncTeXBackend?: LatexCompilerBackend | null;
  /** True when this engine can run Biber in-browser for biblatex projects. */
  supportsBiber?: boolean;
};

export type LatexCompilerPackageResolution = {
  requested: string;
  resolved?: string;
  source: 'cache' | 'bundled' | 'static-mirror' | 'remote' | 'format' | 'miss';
};

export type LatexCompilerRuntimeDiagnostics = {
  status: 'idle' | 'initializing' | 'ready' | 'error';
  backend: LatexCompilerBackend;
  serviceWorker: 'unknown' | 'controlled' | 'fallback-preload' | 'unsupported';
  packageResolutionChain: readonly string[];
  initializationMode?: 'worker' | 'main-thread';
  assetVersion?: string;
  assetFingerprint?: string;
  selfTest?: {
    success: boolean;
    durationMs: number;
    message: string;
  };
  lastPackage?: LatexCompilerPackageResolution;
  /** BusyTeX generated-file readback attempts used to collect auxiliary artifacts after compilation. */
  artifactReadback?: {
    attempts: readonly { path: string; ok: boolean; fileCount: number; error?: string }[];
    mergedFileCount: number;
  };
  error?: string;
};

export type LatexCompilerCapabilities = {
  schemaVersion: 1;
  generatedAt?: string;
  releaseVersion?: string;
  mode: 'busytex-with-swiftlatex-fallback' | 'swiftlatex-pdflatex' | 'unavailable';
  engines: Record<LearnitiveCompiler, LatexCompilerEngineCapability>;
  runtimeAssets?: {
    busytex?: {
      version: string | null;
      fingerprint: string | null;
      moduleUrl: string;
      basePath: string;
      requiredFiles: readonly string[];
      engineRequiredFiles: Partial<Record<LearnitiveCompiler, readonly string[]>>;
    };
  };
  texlive: {
    bundled: {
      available: boolean;
      bundleId: string | null;
      compatibility: string | null;
      fileCount: number;
      textFileCount: number;
      binaryFileCount: number;
    };
    staticMirror: {
      enabled: boolean;
      endpoint: string | null;
      index: string | null;
    };
    remote: {
      enabled: boolean;
      endpoint: string | null;
      configurable: boolean;
    };
    /** Full TeX Live coverage for BusyTeX: local core bundles plus the full tree streamed on demand. */
    fullCoverage?: {
      available: boolean;
      strategy: 'bundled+full-on-demand' | 'local-bundles-only';
      localBundles: readonly string[];
      endpoint: string | null;
      remoteFonts: boolean;
    };
    busytexEndpoint: string | null;
  };
};

export type LatexCompileFile = {
  path: ProjectFilePath;
  content: Uint8Array;
};

export type LatexDiagnostic = {
  severity: LatexDiagnosticSeverity;
  message: string;
  file?: ProjectFilePath;
  line?: number;
  column?: number;
  code?: string;
  raw?: string;
};

export type LatexCompileProgress = {
  phase:
    | 'initializing'
    | 'mounting-files'
    | 'downloading-packages'
    | 'compiling'
    | 'bibliography'
    | 'index'
    | 'rerun'
    | 'finalizing';
  percent?: number;
  message?: string;
};

export type LatexCompileRequest = {
  compiler: LearnitiveCompiler;
  mode?: LatexCompileMode;
  rootFile: ProjectFilePath;
  files: readonly LatexCompileFile[];
  signal?: AbortSignal;
  onProgress?: (progress: LatexCompileProgress) => void;
  /** Internal preview compiles may disable BibTeX/Biber/makeindex/reruns. Existing callers default to auto. */
  auxiliaryPasses?: 'auto' | 'none';
  /** Internal preview compiles that only need PDF/SyncTeX may skip generated-file readback. */
  artifactReadback?: 'auto' | 'none';
};

export type CompileArtifact = {
  path: string;
  kind: 'pdf' | 'log' | 'synctex' | 'aux' | 'bbl' | 'blg' | 'toc' | 'out' | 'other';
  mimeType?: string;
  size?: number;
  generated: boolean;
  text?: boolean;
  data?: Uint8Array;
  textContent?: string;
};

export type LatexBibliographyPlan = {
  bibtex: boolean;
  biberRequested: boolean;
  makeindex: boolean;
  rerun: boolean;
};

export type LatexCompilePerformance = {
  /** Time spent initializing the compiler runtime for this real user compile. */
  runtimeInitMs: number;
  /** Time spent obtaining package data needed by this real user compile. */
  packageFetchMs: number;
  /** Time spent in an explicitly measurable bibliography pass. */
  bibliographyMs: number;
  /** Time spent inside TeX engine compile passes, excluding measured bibliography time. */
  engineCompileMs: number;
  /** Time from the final engine result until the compile result/artifacts are ready. */
  pdfReadyMs: number;
  /** End-to-end duration of the real compile request. */
  totalMs: number;
  /** True when the requested compiler runtime was already initialized before this compile. */
  runtimeWasWarm: boolean;
  /** Number of package resolutions that required a non-cache package source where observable. */
  packagesFetched: number;
};

export type LatexCompileResult = {
  success: boolean;
  compileMode?: LatexCompileMode;
  backend: LatexCompilerBackend;
  compiler: LearnitiveCompiler;
  exitCode: number;
  pdf?: Uint8Array;
  synctex?: Uint8Array;
  log: string;
  diagnostics: readonly LatexDiagnostic[];
  runtimeDiagnostics?: LatexCompilerRuntimeDiagnostics;
  durationMs: number;
  /** Detailed timing for the actual user compile; never populated by hidden test compiles. */
  performance?: LatexCompilePerformance;
  bibliography: LatexBibliographyPlan;
  artifacts?: readonly CompileArtifact[];
};


export type LatexLiveDraftRecord = {
  type: string;
  page?: number;
  x?: number;
  y?: number;
  width?: number;
  height?: number;
  depth?: number;
  char?: number;
  font?: number;
  subtype?: number;
  name?: string;
  raw: Record<string, unknown>;
};

export type LatexLiveDraftRuntimeCertificateDiagnostics = {
  compileSucceeded: boolean;
  recordArtifactFound: boolean;
  recordArtifactPath?: string;
  recordBytes: number;
  directLuaRecordFound: boolean;
  pageRecords: number;
  pdfBytes: number;
  artifactReadbackAttempts: readonly { path: string; ok: boolean; fileCount: number; error?: string }[];
};

export type LatexLiveDraftProbeResult = {
  ok: boolean;
  engine: 'lualatex';
  runtime: 'busytex';
  directLua: boolean;
  memfsRecords: boolean;
  pageCount: number;
  records: readonly LatexLiveDraftRecord[];
  fonts: readonly string[];
  hasGlyphs: boolean;
  hasRules: boolean;
  hasWhatsits: boolean;
  hasMultiplePages: boolean;
  log: string;
  durationMs: number;
  /** Observable R4 evidence, kept separate so partial runtime failures remain diagnosable. */
  certificate: LatexLiveDraftRuntimeCertificateDiagnostics;
  /** Real PDF bytes emitted by the verified BusyTeX LuaLaTeX run. Production Live PDF may only use these bytes after the Lua/MEMFS gate passes. */
  pdf?: Uint8Array;
  reason?: string;
};

export type LatexLiveDraftProbeRequest = {
  signal?: AbortSignal;
  onProgress?: (progress: LatexCompileProgress) => void;
};

export type LatexLiveDraftRenderRequest = {
  rootFile: ProjectFilePath;
  files: readonly LatexCompileFile[];
  signal?: AbortSignal;
  onProgress?: (progress: LatexCompileProgress) => void;
};


export type LatexLiveInstantRenderRequest = {
  rootFile: ProjectFilePath;
  files: readonly LatexCompileFile[];
  /** Canonical body block to render. It is never persisted or written back to project storage. */
  text: string;
  /** Target line width from the last exact R5 SyncTeX generation, in TeX points. */
  hsize: number;
  signal?: AbortSignal;
  onProgress?: (progress: LatexCompileProgress) => void;
};

export type LatexLiveInstantRenderResult = {
  ok: boolean;
  engine: 'lualatex';
  runtime: 'busytex';
  log: string;
  durationMs: number;
  /** Tiny transient PDF containing only the edited block. Never export this as the project PDF. */
  pdf?: Uint8Array;
  reason?: string;
};
export type LatexLiveDraftRenderResult = {
  ok: boolean;
  engine: 'lualatex';
  runtime: 'busytex';
  log: string;
  durationMs: number;
  pdf?: Uint8Array;
  /** SyncTeX bytes emitted by the exact same R5 LuaLaTeX compile as `pdf`. */
  synctex?: Uint8Array;
  reason?: string;
};

export interface LatexLiveDraftCompiler {
  /** Self-contained R4 runtime certification. It must not depend on the user's manuscript. */
  probe(request: LatexLiveDraftProbeRequest): Promise<LatexLiveDraftProbeResult>;
  /** R5 production rendering of the canonical project snapshot, without feasibility instrumentation. */
  render(request: LatexLiveDraftRenderRequest): Promise<LatexLiveDraftRenderResult>;
  /** R6 may pre-warm its isolated browser runtime after the first exact R5 PDF. */
  warmInstant?(): Promise<void>;
  /** R6 optional block-only renderer. Absence means callers must use R5 only. */
  renderInstant?(request: LatexLiveInstantRenderRequest): Promise<LatexLiveInstantRenderResult>;
  /** Cancels only R6 work; must not tear down the authoritative R5 compiler. */
  cancelInstant?(): void;
  /** Reclaims only the isolated R6 runtime/worker without touching authoritative R5. */
  disposeInstant?(): void;
  cancel(): void;
  dispose(): void;
}

export interface LatexCompiler {
  readonly backend: LatexCompilerBackend;

  supports(compiler: LearnitiveCompiler): boolean;
  getCapabilities?(signal?: AbortSignal): Promise<LatexCompilerCapabilities>;
  getRuntimeDiagnostics?(): LatexCompilerRuntimeDiagnostics | undefined;
  initialize(signal?: AbortSignal): Promise<void>;
  compile(request: LatexCompileRequest): Promise<LatexCompileResult>;
  cancel(): void;
  dispose(): void;
}
