/**
 * Paper domain model for the publisher.
 *
 * A "paper" is the publishable artifact an investigator produces from a research project's
 * results. Papers are persisted (no migration) inside `ResearchProject.content.papers[]` and
 * written via the existing `PUT /projects/{id}/detail` merge endpoint.
 *
 * The integrity gate (INV-3 of the academic-research spec — "everything is sourced") and the
 * human-approval publish event (INV-1 — "human in the loop") are modelled here as pure functions
 * so they are unit-testable and cannot be silently bypassed by the UI.
 */

export type PaperStatus = 'draft' | 'published';

export interface SourceRef {
  id: string;
  title: string;
  authors?: string;
  /** DOI or URL of the source. */
  doiOrUrl?: string;
  /** The human has confirmed this reference actually exists (not hallucinated). */
  verifiedReal: boolean;
}

export interface PaperApproval {
  approvedByUserId: string;
  approvedByName: string;
  /** ISO timestamp of the human-approval event. */
  approvedAt: string;
  note?: string;
}

export interface PaperEdit {
  /** ISO timestamp. */
  at: string;
  action: string;
}

export interface Paper {
  id: string;
  title: string;
  titleEn?: string;
  abstractVi: string;
  abstractEn?: string;
  body: string;
  sources: SourceRef[];
  status: PaperStatus;
  approval?: PaperApproval | null;
  publishedAt?: string | null;
  createdAt: string;
  updatedAt: string;
  /** Full edit history (INV-6 — traceability). */
  editHistory: PaperEdit[];
}

const nowIso = (): string => new Date().toISOString();

/** Browser-native UUID, with a non-secure-context fallback. */
export function newId(): string {
  if (typeof crypto !== 'undefined' && typeof (crypto as Crypto).randomUUID === 'function') {
    return crypto.randomUUID();
  }
  return `p_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
}

export function emptyPaper(): Paper {
  const ts = nowIso();
  return {
    id: newId(),
    title: '',
    titleEn: '',
    abstractVi: '',
    abstractEn: '',
    body: '',
    sources: [],
    status: 'draft',
    approval: null,
    publishedAt: null,
    createdAt: ts,
    updatedAt: ts,
    editHistory: [{ at: ts, action: 'Tạo bản thảo' }],
  };
}

export function emptySource(): SourceRef {
  return { id: newId(), title: '', authors: '', doiOrUrl: '', verifiedReal: false };
}

/** Safely read the papers array out of a project's `content` JSONB. */
export function extractPapers(content: Record<string, unknown> | null | undefined): Paper[] {
  const raw = (content ?? {})['papers'];
  if (!Array.isArray(raw)) return [];
  return raw.filter(
    (p): p is Paper => !!p && typeof p === 'object' && typeof (p as Paper).id === 'string',
  );
}

export function findPaper(papers: Paper[], paperId: string): Paper | undefined {
  return papers.find((p) => p.id === paperId);
}

/** Replace the paper with the same id, or append it. Returns a new array (immutable). */
export function upsertPaper(papers: Paper[], paper: Paper): Paper[] {
  const idx = papers.findIndex((p) => p.id === paper.id);
  if (idx === -1) return [...papers, paper];
  const next = papers.slice();
  next[idx] = paper;
  return next;
}

/**
 * Integrity gate (INV-3): the human-readable reasons a paper may NOT yet be published.
 * An empty array ⇒ the paper satisfies the integrity requirements.
 */
export function integrityIssues(paper: Paper): string[] {
  const issues: string[] = [];
  if (!paper.title.trim()) issues.push('Thiếu tiêu đề bài báo.');
  if (!paper.abstractVi.trim()) issues.push('Thiếu tóm tắt (tiếng Việt).');
  if (!paper.body.trim()) issues.push('Nội dung bài báo còn trống.');
  if (paper.sources.length === 0) {
    issues.push('Chưa có nguồn tham khảo nào — mọi luận điểm phải có nguồn.');
  }
  const unverified = paper.sources.filter((s) => !s.verifiedReal).length;
  if (unverified > 0) issues.push(`${unverified} nguồn chưa được xác minh là có thật.`);
  return issues;
}

/** A paper may be published only if it is still a draft and the integrity gate is satisfied. */
export function canPublish(paper: Paper): boolean {
  return paper.status !== 'published' && integrityIssues(paper).length === 0;
}

/** Touch `updatedAt` and append an edit-history entry (INV-6). */
export function touchPaper(paper: Paper, action: string): Paper {
  const at = nowIso();
  return { ...paper, updatedAt: at, editHistory: [...paper.editHistory, { at, action }] };
}

/**
 * Apply the human-approval publish event (INV-1). Throws if the integrity gate is not satisfied,
 * so a paper can never reach `published` except through an explicit, gate-passing human action.
 */
export function publishPaper(
  paper: Paper,
  approver: { id: string; name: string },
  note?: string,
): Paper {
  if (!canPublish(paper)) {
    throw new Error('Không thể xuất bản: bài báo chưa đạt cổng kiểm soát tính toàn vẹn.');
  }
  const at = nowIso();
  return {
    ...paper,
    status: 'published',
    approval: {
      approvedByUserId: approver.id,
      approvedByName: approver.name,
      approvedAt: at,
      note: note?.trim() || undefined,
    },
    publishedAt: at,
    updatedAt: at,
    editHistory: [...paper.editHistory, { at, action: `Phê duyệt & xuất bản bởi ${approver.name}` }],
  };
}
