import { getBinary, getJson, postJson } from "./client";

export interface ServiceInfo {
  service: string;
  version: number;
}

export interface RunRecord {
  schemaVersion: number;
  runId: string;
  runSeq: number | null;
  runDir: string;
  validationTime: string | null;
  syncMode: string | null;
  startedAt: string | null;
  finishedAt: string | null;
  wallMs: number | null;
  artifactPaths: Record<string, string>;
  counts: {
    publicationPoints: number;
    objects: number;
    freshObjects: number;
    cachedObjects: number;
    rejectedObjects: number;
    freshRejectedObjects: number;
    cachedRejectedObjects: number;
    trustAnchors: number;
    vrps: number;
    aspas: number;
    warnings: number;
  };
  indexStatus: string;
  indexError: string | null;
}

export interface RepositoryRecord {
  schemaVersion: number;
  runId: string;
  repoId: string;
  uri: string;
  host: string;
  transport: string;
  publicationPoints: number;
  objects: number;
  rejectedObjects: number;
  downloadBytes: number | null;
  syncDurationMsTotal: number;
  phases: Record<string, number>;
  terminalStates: Record<string, number>;
}

export interface PublicationPointRecord {
  schemaVersion: number;
  runId: string;
  ppId: string;
  repoId: string;
  nodeId: number | null;
  parentNodeId: number | null;
  rsyncBaseUri: string | null;
  manifestRsyncUri: string | null;
  publicationPointRsyncUri: string | null;
  rrdpNotificationUri: string | null;
  source: string | null;
  repoSyncSource: string | null;
  repoSyncPhase: string | null;
  repoSyncDurationMs: number | null;
  repoSyncError: string | null;
  repoTerminalState: string | null;
  thisUpdate: string | null;
  nextUpdate: string | null;
  verifiedAt: string | null;
  objects: number;
  rejectedObjects: number;
  warnings: number;
}

export interface ObjectInstanceRecord {
  schemaVersion: number;
  runId: string;
  objectInstanceId: string;
  uri: string;
  uriHash: string;
  sha256: string;
  objectType: string;
  result: string;
  detailSummary: string | null;
  repoId: string;
  ppId: string;
  sourceSection: string;
  rejected: boolean;
  rejectReason: string | null;
}

export interface ObjectProjectionRecord {
  schemaVersion?: number;
  objectType?: string;
  sha256?: string;
  uri?: string;
  parseStatus?: string;
  errorSummary?: string | null;
  projection?: unknown;
}

export interface ValidationIssueRecord {
  stage?: string;
  severity?: string;
  reasonCode?: string;
  summary?: string;
}

export interface ObjectValidationRecord {
  objectInstanceId: string;
  uri: string;
  sha256: string;
  objectType: string;
  finalStatus: string;
  auditResult: string;
  detailSummary: string | null;
  rejected: boolean;
  rejectReason: string | null;
  sourceSection: string;
  explainAvailable: boolean;
  authoritative: boolean;
  fileValidation: {
    status: string;
    stage: string;
    issues: ValidationIssueRecord[];
    detailSummary: string | null;
  };
  chainValidation: {
    status: string;
    stage: string;
    issues: ValidationIssueRecord[];
    note?: string;
    edgesPage?: { nextCursor: string | null; limit: number };
  };
}

export interface ChainEdgeRecord {
  relation: string;
  fromUri: string;
  toUri: string;
  toObjectInstanceId: string | null;
  toSha256: string | null;
  status: string;
  evidence: unknown;
}

export interface ValidationExplainRecord {
  schemaVersion: number;
  explainVersion: number;
  runId: string;
  objectInstanceId: string;
  uri: string;
  sha256: string;
  objectType: string;
  finalStatus: string;
  auditResult: string;
  detailSummary: string | null;
  authoritative: boolean;
  explainMode: string;
  generatedAt: string;
  parsevalidate: unknown;
  chainvalidate: unknown;
  chainEdges: ChainEdgeRecord[];
}

export interface ObjectUriIndexRecord {
  runId: string;
  uri: string;
  sha256: string;
  objectInstanceId: string;
  repoId: string;
  ppId: string;
}

export interface ExportJobRecord {
  schemaVersion: number;
  jobId: string;
  runId: string;
  scope: string;
  repoId: string | null;
  ppId: string | null;
  status: string;
  createdAt: string;
  finishedAt: string | null;
  outputPath: string | null;
  objectCount: number;
  bytesWritten: number;
  error: string | null;
}

export type CountsByKey = Record<string, number>;

export async function getServiceInfo() {
  return getJson<ServiceInfo>("/api/v1");
}

export async function getLatestRun() {
  return getJson<RunRecord>("/api/v1/latest_run");
}

export async function getRunSummary(runId: string) {
  return getJson<Record<string, number>>(`/api/v1/runs/${runId}/summary`);
}

export async function getStatsObjectTypes(runId: string) {
  return getJson<CountsByKey>(`/api/v1/runs/${runId}/stats/object-types`);
}

export async function getStatsValidation(runId: string) {
  return getJson<CountsByKey>(`/api/v1/runs/${runId}/stats/validation`);
}

export async function getStatsReasons(runId: string) {
  return getJson<CountsByKey>(`/api/v1/runs/${runId}/stats/reasons`);
}

export async function getStatsDownloads(runId: string) {
  return getJson<Record<string, unknown>>(`/api/v1/runs/${runId}/stats/downloads`);
}

export async function listRepos(runId: string, limit = 5, cursor?: string | null) {
  return getJson<RepositoryRecord[]>(`/api/v1/runs/${runId}/repos`, { limit, cursor: cursor ?? undefined });
}

export async function listPublicationPointsForRepo(runId: string, repoId: string, limit = 50, cursor?: string | null) {
  return getJson<PublicationPointRecord[]>(`/api/v1/runs/${runId}/repos/${repoId}/publication-points`, {
    limit,
    cursor: cursor ?? undefined
  });
}

export async function listObjectsForPublicationPoint(runId: string, ppId: string, limit = 50, cursor?: string | null) {
  return getJson<ObjectInstanceRecord[]>(`/api/v1/runs/${runId}/publication-points/${ppId}/objects`, {
    limit,
    cursor: cursor ?? undefined
  });
}

export async function getObject(runId: string, objectInstanceId: string) {
  return getJson<ObjectInstanceRecord>(`/api/v1/runs/${runId}/objects/${objectInstanceId}`);
}

export async function getObjectByUri(runId: string, uri: string) {
  return getJson<ObjectUriIndexRecord>(`/api/v1/runs/${runId}/objects/by-uri`, { uri });
}

export async function getObjectParsed(runId: string, objectInstanceId: string) {
  return getJson<ObjectProjectionRecord | null>(`/api/v1/runs/${runId}/objects/${objectInstanceId}/parsed`);
}

export async function getObjectValidation(runId: string, objectInstanceId: string) {
  return getJson<ObjectValidationRecord>(`/api/v1/runs/${runId}/objects/${objectInstanceId}/validation`);
}

export async function getObjectChain(runId: string, objectInstanceId: string) {
  return getJson<ChainEdgeRecord[]>(`/api/v1/runs/${runId}/objects/${objectInstanceId}/chain`);
}

export async function listManifestFiles(runId: string, objectInstanceId: string, limit = 50, cursor?: string | null) {
  return getJson<unknown[]>(`/api/v1/runs/${runId}/objects/${objectInstanceId}/parsed/manifest-files`, {
    limit,
    cursor: cursor ?? undefined
  });
}

export async function listRevokedCertificates(runId: string, objectInstanceId: string, limit = 50, cursor?: string | null) {
  return getJson<unknown[]>(`/api/v1/runs/${runId}/objects/${objectInstanceId}/parsed/revoked-certs`, {
    limit,
    cursor: cursor ?? undefined
  });
}

export async function explainObjectValidation(runId: string, objectInstanceId: string, forceRefresh = false) {
  return postJson<ValidationExplainRecord>(`/api/v1/runs/${runId}/objects/${objectInstanceId}/validation/explain`, {
    forceRefresh
  });
}

export async function downloadRawObject(runId: string, objectInstanceId: string) {
  return getBinary(`/api/v1/runs/${runId}/objects/${objectInstanceId}/raw`);
}

export async function createObjectSetExport(runId: string, objectInstanceIds: string[]) {
  return postJson<ExportJobRecord>(`/api/v1/runs/${runId}/exports`, {
    objectInstanceIds,
    scope: "object_set"
  });
}

export async function createPublicationPointExport(runId: string, ppId: string) {
  return postJson<ExportJobRecord>(`/api/v1/runs/${runId}/exports`, {
    ppId,
    scope: "publication_point"
  });
}

export async function getExportJob(runId: string, jobId: string) {
  return getJson<ExportJobRecord>(`/api/v1/runs/${runId}/exports/${jobId}`);
}
