import type { StreamWriter } from '@qwik.dev/core/internal';
import type { Render, RenderOptions } from '@qwik.dev/core/server';
import type { QwikRouterConfig } from '@qwik.dev/router';
import type { ServerRenderOptions } from '@qwik.dev/router/middleware/request-handler';

export interface System {
  createMainProcess: (() => Promise<MainContext>) | null;
  createLogger: () => Promise<Logger>;
  getOptions: () => SsgGenerateOptions;
  ensureDir: (filePath: string) => Promise<void>;
  access: (path: string) => Promise<boolean>;
  createWriteStream: (filePath: string) => StaticStreamWriter;
  createTimer: () => () => number;
  getRouteFilePath: (pathname: string, isHtml: boolean) => string;
  getLoaderFilePath: (pathname: string, loaderId: string, manifestHash: string) => string;
  getEnv: (key: string) => string | undefined;
  platform: { [key: string]: any };
}

export interface StaticStreamWriter extends StreamWriter {
  write: (chunk: string | Buffer) => void;
  end(callback?: () => void): void;
  on(event: 'error', callback: (err: Error) => void): void;
}

export interface MainContext {
  hasAvailableWorker: () => boolean;
  render: (staticRoute: SsgRenderInput) => Promise<SsgWorkerRenderResult>;
  close: () => Promise<void>;
}

export interface Logger {
  info: (...msgs: any[]) => void;
  error: (...msgs: any[]) => void;
  debug: (...msgs: any[]) => void;
}

/** @public */
export interface SsgRenderOptions extends RenderOptions {
  /** File system directory where the static files should be written. */
  outDir: string;
  /**
   * The URL `origin`, which is a combination of the scheme (protocol) and hostname (domain). For
   * example, `https://qwik.dev` has the protocol `https://` and domain `qwik.dev`. However, the
   * `origin` does not include a `pathname`.
   *
   * The `origin` is used to provide a full URL during Static Site Generation (SSG), and to simulate
   * a complete URL rather than just the `pathname`. For example, in order to render a correct
   * canonical tag URL or URLs within the `sitemap.xml`, the `origin` must be provided too.
   *
   * If the site also starts with a pathname other than `/`, please use the `basePathname` option in
   * the Qwik Router config options.
   */
  origin: string;
  /**
   * Maximum number of workers to use while generating the static pages. Defaults to the number of
   * CPUs available.
   */
  maxWorkers?: number;
  /** Maximum number of tasks to be running at one time per worker. Defaults to `20`. */
  maxTasksPerWorker?: number;
  /**
   * File system path to write the `sitemap.xml` to. Defaults to `sitemap.xml` and written to the
   * root of the `outDir`. Setting to `null` will prevent the sitemap from being created.
   */
  sitemapOutFile?: string | null;
  /** Log level. `'quiet'` suppresses per-page output, `'debug'` enables verbose logging. */
  log?: 'debug' | 'quiet';
  /**
   * Set to `false` if the generated static HTML files should not be written to disk. Setting to
   * `false` is useful if the SSG should only write the per-loader data files to disk. Defaults to
   * `true`.
   */
  emitHtml?: boolean;
  /**
   * Set to `false` if the generated per-loader data files should not be written to disk. Defaults
   * to `true`.
   */
  emitData?: boolean;
  /**
   * Defines file system routes relative to the source `routes` directory that should be static
   * generated. Accepts wildcard behavior. This should not include the "base" pathname. If not
   * provided, all routes will be static generated. `exclude` always takes priority over `include`.
   */
  include?: string[];
  /**
   * Defines file system routes relative to the source `routes` directory that should not be static
   * generated. Accepts wildcard behavior. This should not include the "base" pathname. `exclude`
   * always takes priority over `include`.
   */
  exclude?: string[];
}

/** @public */
export interface SsgOptions extends SsgRenderOptions {
  /** Defaults to `/` */
  basePathname?: string;

  rootDir?: string;
}

/**
 * Internal SSG options that include the render function and router config.
 *
 * @public
 */
export interface SsgGenerateOptions extends SsgOptions {
  /** SSR render function (default export from `entry.ssr`); worker-only — the main entry omits it. */
  render: Render;
  /** The Qwik Router Config object (default export from `@qwik-router-config`). */
  qwikRouterConfig: QwikRouterConfig;

  /** Path or URL to the worker entry file (`run-ssg-worker.js`); workers are spawned from it. */
  workerFilePath?: string | URL;
}

export interface SsgHandlerOptions extends SsgRenderOptions, ServerRenderOptions {
  qwikRouterConfig?: QwikRouterConfig;
}

export type WorkerInputMessage = SsgRenderInput | WorkerCloseMessage;

export type WorkerOutputMessage = SsgWorkerRenderResult | WorkerCloseMessage;

export interface SsgRenderInput extends SsgRoute {
  type: 'render';
}

export interface SsgRoute {
  pathname: string;
  params: Record<string, string> | undefined;
}

export interface WorkerCloseMessage {
  type: 'close';
}

export interface SsgWorkerRenderResult {
  type: 'render';
  pathname: string;
  url: string;
  ok: boolean;
  error: { message: string; stack: string | undefined } | null;
  filePath: string | null;
  contentType: string | null;
  resourceType: 'page' | null;
}

/** @public */
export interface SsgResult {
  duration: number;
  rendered: number;
  errors: number;
  staticPaths: string[];
}
