export const PAPER_MEMORY_SCHEMA_VERSION = 1 as const;
export const PAPER_MEMORY_EXTRACTOR_VERSION = 'pdfjs-scientific-v1' as const;
export const PAPER_MEMORY_CHUNKING_VERSION = 'scientific-400-900-v1' as const;
export const PAPER_MEMORY_LEXICAL_VERSION = 'scientific-lexical-v1' as const;

export type PaperIndexingStatus =
  | 'queued'
  | 'extracting'
  | 'chunking'
  | 'embedding'
  | 'saving'
  | 'ready'
  | 'ocr-required'
  | 'cancelled'
  | 'error'
  | 'reindex-required';

export type PaperEmbeddingDescriptor = {
  engine: string;
  model: string;
  modelVersion: string;
  dimensions: number;
};

export type PaperRecord = {
  id: string;
  fileName: string;
  title?: string;
  authors?: string[];
  year?: number;
  doi?: string;
  arxivId?: string;
  pageCount: number;
  addedAt: number;
  fingerprint: string;
  indexingStatus: PaperIndexingStatus;
  activeGenerationId?: string;
  error?: string;
};


export type PaperCollection = {
  id: string;
  name: string;
  paperIds: string[];
  createdAt: number;
  updatedAt: number;
};

export type PaperResearchNote = {
  id: string;
  createdAt: number;
  updatedAt: number;
  title?: string;
  body: string;
  quote?: string;
  paperId?: string;
  paperTitle?: string;
  pageStart?: number;
  pageEnd?: number;
  tags: string[];
};

export type LivingLiteratureResult = {
  id: string;
  title: string;
  authors: string[];
  year?: number;
  doi?: string;
  pmid?: string;
  arxivId?: string;
  url?: string;
  openAccessPdfUrl?: string;
  sourceProviders?: string[];
};

export type LivingLiteratureSearch = {
  id: string;
  name: string;
  query: string;
  createdAt: number;
  updatedAt: number;
  lastCheckedAt?: number;
  newResultCount: number;
  knownResultIds: string[];
  latestResults: LivingLiteratureResult[];
};

export type SystematicReviewDecision = 'include' | 'maybe' | 'exclude' | 'unreviewed';

export type SystematicReviewStudy = {
  paperId: string;
  decision: SystematicReviewDecision;
  reason?: string;
  aiSuggestion?: Exclude<SystematicReviewDecision, 'unreviewed'>;
  aiRationale?: string;
  riskOfBias?: 'low' | 'some-concerns' | 'high' | 'insufficient';
  riskOfBiasRationale?: string;
};

export type SystematicReviewRecord = {
  id: string;
  title: string;
  question: string;
  createdAt: number;
  updatedAt: number;
  searchQuery?: string;
  studies: SystematicReviewStudy[];
};

export type PaperMemoryManifest = {
  schemaVersion: typeof PAPER_MEMORY_SCHEMA_VERSION;
  memoryId: string;
  updatedAt: number;
  papers: PaperRecord[];
  collections?: PaperCollection[];
  notes?: PaperResearchNote[];
  systematicReviews?: SystematicReviewRecord[];
  livingLiteratureSearches?: LivingLiteratureSearch[];
  researchArtifacts?: PaperStoredResearchArtifact[];
  embedding?: PaperEmbeddingDescriptor;
};

export type PdfTextLine = {
  text: string;
  x: number;
  y: number;
  width: number;
  height: number;
  fontSize: number;
};

export type ExtractedPdfPage = {
  pageNumber: number;
  width: number;
  height: number;
  lines: PdfTextLine[];
  text: string;
};

export type ScientificBlockKind =
  | 'abstract'
  | 'paragraph'
  | 'heading'
  | 'equation-context'
  | 'figure-caption'
  | 'table-caption'
  | 'theorem'
  | 'references';

export type ScientificBlock = {
  id: string;
  kind: ScientificBlockKind;
  text: string;
  pageStart: number;
  pageEnd: number;
  heading?: string;
  section?: string;
};

export type PaperChunk = {
  id: string;
  paperId: string;
  kind: Exclude<ScientificBlockKind, 'heading'>;
  text: string;
  pageStart: number;
  pageEnd: number;
  heading?: string;
  section?: string;
  contentHash: string;
};

export type PaperLexicalPosting = {
  term: string;
  chunkIndexes: number[];
};

export type PaperLexicalIndex = {
  version: typeof PAPER_MEMORY_LEXICAL_VERSION;
  documentLengths: number[];
  averageDocumentLength: number;
  postings: PaperLexicalPosting[];
};

export type PaperEmbeddingIndex = PaperEmbeddingDescriptor & {
  vectors: ArrayBuffer;
};

export type ExtractedPaperMetadata = {
  title?: string;
  authors?: string[];
  year?: number;
  doi?: string;
  arxivId?: string;
};

export type PaperExtraction = {
  pageCount: number;
  pages: ExtractedPdfPage[];
  blocks: ScientificBlock[];
  metadata: ExtractedPaperMetadata;
  scanned: boolean;
};

export type PaperIndexGeneration = {
  schemaVersion: typeof PAPER_MEMORY_SCHEMA_VERSION;
  extractorVersion: typeof PAPER_MEMORY_EXTRACTOR_VERSION;
  chunkingVersion: typeof PAPER_MEMORY_CHUNKING_VERSION;
  generationId: string;
  paperId: string;
  createdAt: number;
  pages: ExtractedPdfPage[];
  blocks: ScientificBlock[];
  chunks: PaperChunk[];
  lexical?: PaperLexicalIndex;
  embedding?: PaperEmbeddingIndex;
};

export type PaperMemoryIndexProgress = {
  paperId: string;
  phase: 'extracting' | 'chunking' | 'embedding' | 'saving';
  completed: number;
  total: number;
};


export type PaperMemoryCapabilities = {
  indexedDb: boolean;
  opfs: boolean;
  workers: boolean;
  storageEstimate: boolean;
  persistentStorage: boolean;
  preferredPdfBackend: 'opfs' | 'indexeddb';
  persisted?: boolean;
  browserUsageBytes?: number;
  quotaBytes?: number;
};

export type PaperMemoryRetrievalTiming = {
  loadIndexesMs: number;
  embedQueryMs: number;
  rankMs: number;
  totalMs: number;
};

export type PaperMemoryRetrievalDebugResult = {
  query: string;
  requestedPaperIds?: readonly string[];
  consideredPaperIds: readonly string[];
  semanticRequested: boolean;
  semanticUsed: boolean;
  diversified: boolean;
  timing: PaperMemoryRetrievalTiming;
  results: readonly PaperMemorySearchResult[];
};

export type PaperMemoryUsage = {
  sourceBytes: number;
  metadataBytes: number;
  vectorBytes: number;
};

export interface PaperMemoryStore {
  loadManifest(memoryId: string): Promise<PaperMemoryManifest>;
  saveManifest(manifest: PaperMemoryManifest): Promise<void>;
  storeSourcePdf(memoryId: string, paperId: string, bytes: ArrayBuffer): Promise<void>;
  readSourcePdf(memoryId: string, paperId: string): Promise<ArrayBuffer | undefined>;
  loadActiveIndex(memoryId: string, paperId: string): Promise<PaperIndexGeneration | undefined>;
  commitIndex(memoryId: string, record: PaperRecord, generation: PaperIndexGeneration): Promise<void>;
  removePaper(memoryId: string, paperId: string): Promise<void>;
  clear(memoryId: string): Promise<void>;
  estimateUsage(memoryId: string): Promise<PaperMemoryUsage>;
}

export type PaperPreparedIndex = {
  extraction: PaperExtraction;
  chunks: PaperChunk[];
};

export interface PaperMemoryExtractor {
  extractAndChunk(
    paperId: string,
    bytes: ArrayBuffer,
    signal?: AbortSignal,
    onProgress?: (progress: { phase: 'extracting' | 'chunking'; completed: number; total: number }) => void,
  ): Promise<PaperPreparedIndex>;
  dispose(): void;
}

export interface PaperMemoryPlatform {
  store: PaperMemoryStore;
  capabilities(): Promise<PaperMemoryCapabilities>;
  requestPersistence(): Promise<boolean | undefined>;
  createExtractor(): PaperMemoryExtractor;
  dispose(): void;
}

export type PaperMemorySearchResult = {
  paper: PaperRecord;
  chunk: PaperChunk;
  lexicalScore: number;
  semanticScore?: number;
  score: number;
};

export type PaperMemorySearchOptions = {
  paperIds?: readonly string[];
  limit?: number;
  diversify?: boolean | 'auto';
};

export type PaperResearchEvidence = {
  sourceId: string;
  paperId: string;
  paperTitle: string;
  pageStart: number;
  pageEnd: number;
  excerpt: string;
};

export type PaperResearchCell = {
  value: string;
  evidence: readonly PaperResearchEvidence[];
};

export type PaperStudySnapshot = {
  kind: 'study-snapshot';
  paperId: string;
  paperTitle: string;
  fields: Readonly<Record<string, PaperResearchCell>>;
};

export type PaperExtractionMatrixRow = {
  paperId: string;
  paperTitle: string;
  cells: Readonly<Record<string, PaperResearchCell>>;
};

export type PaperExtractionMatrix = {
  kind: 'extraction-matrix';
  fields: readonly string[];
  rows: readonly PaperExtractionMatrixRow[];
};

export type PaperComparisonArtifact = {
  kind: 'comparison';
  matrix: PaperExtractionMatrix;
  synthesis: string;
};

export type PaperContradictionGroup = {
  label: string;
  paperIds: readonly string[];
  explanation: string;
};

export type PaperContradictionArtifact = {
  kind: 'contradictions';
  groups: readonly PaperContradictionGroup[];
  interpretation: string;
  matrix: PaperExtractionMatrix;
};

export type PaperEvidenceClassification = 'supports' | 'mixed' | 'does-not-support' | 'insufficient';

export type PaperEvidenceBalanceStudy = {
  paperId: string;
  paperTitle: string;
  classification: PaperEvidenceClassification;
  strength: 'strong' | 'moderate' | 'weak' | 'insufficient';
  rationale: string;
  evidence: readonly PaperResearchEvidence[];
};

export type PaperEvidenceBalanceArtifact = {
  kind: 'evidence-balance';
  proposition: string;
  counts: Readonly<Record<PaperEvidenceClassification, number>>;
  studies: readonly PaperEvidenceBalanceStudy[];
};

export type PaperTableExtractionArtifact = {
  kind: 'paper-table';
  title: string;
  columns: readonly string[];
  rows: readonly (readonly string[])[];
  evidence: readonly PaperResearchEvidence[];
};



export type PaperVerificationClassification = 'supported' | 'partial' | 'conflicting' | 'not-verified';

export type PaperVerificationArtifact = {
  kind: 'verification';
  claim: string;
  classification: PaperVerificationClassification;
  rationale: string;
  evidence: readonly PaperResearchEvidence[];
  independentlyRetrieved: true;
};

export type PaperDeepResearchStage = 'retrieve' | 'extract' | 'structure' | 'synthesise' | 'verify';

export type PaperDeepResearchArtifact = {
  kind: 'deep-research';
  question: string;
  stages: readonly PaperDeepResearchStage[];
  synthesis: string;
  verification: PaperVerificationArtifact;
  matrix: PaperExtractionMatrix;
};

export type PaperResearchInsightsArtifact = {
  kind: 'research-insights';
  query: string;
  coverage: { paperCount: number; evidencePassages: number; scopeLabel: string };
  currentApproaches: readonly string[];
  potentialGaps: readonly string[];
  noveltySignals: readonly string[];
  hypotheses: readonly string[];
  evidence: readonly PaperResearchEvidence[];
};

export type PaperStoredResearchArtifact = {
  id: string;
  createdAt: number;
  query: string;
  artifact: PaperResearchArtifact;
};

export type PaperResearchArtifact =
  | PaperStudySnapshot
  | PaperExtractionMatrix
  | PaperComparisonArtifact
  | PaperContradictionArtifact
  | PaperEvidenceBalanceArtifact
  | PaperTableExtractionArtifact
  | PaperVerificationArtifact
  | PaperDeepResearchArtifact
  | PaperResearchInsightsArtifact;
