// lib/mines/data-quality.js
//
// Aggregations for the per-project Data tab and the import-progress API.
// Import-safe: pure reads, no side effects (used by Server Components + routes).

import { getDb } from '../db.js';

// extraction_status → coarse progress bucket. The verbatim status counts are
// preserved in each category's status_breakdown; these buckets drive the
// progress bar and the GET /import response.
const STATUS_BUCKETS = {
  queued: 'queued',
  extracting: 'running',
  chunking: 'running',
  embedding: 'running',
  complete: 'complete',
  embedding_failed: 'complete', // text extracted; only the vector step degraded
  done: 'complete',
  failed: 'failed',
  error: 'failed',
  ocr_skipped: 'skipped',
  catalog_only: 'skipped',
  unsupported: 'skipped',
  skipped: 'skipped',
};

function bucketFor(status) {
  return STATUS_BUCKETS[status] || 'queued';
}

/**
 * Full data-quality snapshot for a mines project.
 *
 * @param {string} projectId  mines_projects.id
 * @returns {{
 *   project_id: string,
 *   categories: Array<{ document_category, document_count, chunk_count, status_breakdown }>,
 *   totals: { documents, chunks },
 *   spatial_assets_count: number,
 *   completeness_score: number,
 *   progress: { total_files, queued, running, complete, failed, skipped },
 * }}
 */
export function getProjectDataQuality(projectId) {
  const db = getDb();

  const docRows = db.prepare(`
    SELECT document_category, extraction_status, COUNT(*) AS n
    FROM mines_source_documents
    WHERE project_id = ?
    GROUP BY document_category, extraction_status
  `).all(projectId);

  const chunkRows = db.prepare(`
    SELECT document_category, COUNT(*) AS n
    FROM mines_document_chunks
    WHERE project_id = ?
    GROUP BY document_category
  `).all(projectId);

  const spatialRow = db.prepare(
    'SELECT COUNT(*) AS n FROM mines_spatial_assets WHERE project_id = ?'
  ).get(projectId);

  // Build per-category aggregates.
  const catMap = new Map();
  const progress = { total_files: 0, queued: 0, running: 0, complete: 0, failed: 0, skipped: 0 };

  for (const row of docRows) {
    const cat = row.document_category;
    if (!catMap.has(cat)) {
      catMap.set(cat, { document_category: cat, document_count: 0, chunk_count: 0, status_breakdown: {} });
    }
    const entry = catMap.get(cat);
    entry.document_count += row.n;
    entry.status_breakdown[row.extraction_status] = (entry.status_breakdown[row.extraction_status] || 0) + row.n;

    progress.total_files += row.n;
    progress[bucketFor(row.extraction_status)] += row.n;
  }

  for (const row of chunkRows) {
    if (!catMap.has(row.document_category)) {
      catMap.set(row.document_category, {
        document_category: row.document_category,
        document_count: 0,
        chunk_count: 0,
        status_breakdown: {},
      });
    }
    catMap.get(row.document_category).chunk_count = row.n;
  }

  const categories = [...catMap.values()].sort((a, b) =>
    a.document_category.localeCompare(b.document_category)
  );

  // Completeness: fraction of categories (with ≥1 doc) that have ≥1 complete doc.
  const categoriesWithDocs = categories.filter(c => c.document_count > 0);
  const categoriesComplete = categoriesWithDocs.filter(
    c => (c.status_breakdown.complete || 0) + (c.status_breakdown.embedding_failed || 0) + (c.status_breakdown.done || 0) > 0
  );
  const completeness_score = categoriesWithDocs.length === 0
    ? 0
    : Math.round((categoriesComplete.length / categoriesWithDocs.length) * 100) / 100;

  const totalChunks = chunkRows.reduce((sum, r) => sum + r.n, 0);

  return {
    project_id: projectId,
    categories,
    totals: { documents: progress.total_files, chunks: totalChunks },
    spatial_assets_count: spatialRow?.n ?? 0,
    completeness_score,
    progress,
  };
}

/**
 * Compact import-progress shape for GET /api/mines/projects/[id]/import.
 * @returns {{ total_files, queued, running, complete, failed, skipped }}
 */
export function getImportProgress(projectId) {
  return getProjectDataQuality(projectId).progress;
}
