package main

import (
	"fmt"
	"time"

	"fn-registry/functions/infra"
)

// snapshotFromRegistry reads registry.db.functions and inserts one row in
// function_versions per (function_id, content_hash) tuple with source='index'.
// Duplicate rows (same hash for same function from the same source) are
// silently ignored — so this can be re-run after every `fn index` to capture
// only NEW versions.
//
// Returns (inserted_rows, total_seen, error).
func snapshotFromRegistry(callDB *DB, registryPath string) (int, int, error) {
	rconn, err := infra.SQLiteOpen(registryPath, "")
	if err != nil {
		return 0, 0, fmt.Errorf("open registry: %w", err)
	}
	defer rconn.Close()

	rows, err := rconn.Query("SELECT id, content_hash, version FROM functions WHERE content_hash != ''")
	if err != nil {
		return 0, 0, fmt.Errorf("query functions: %w", err)
	}
	defer rows.Close()

	now := time.Now().UTC().Unix()
	tx, err := callDB.conn.Begin()
	if err != nil {
		return 0, 0, err
	}
	stmt, err := tx.Prepare(`INSERT OR IGNORE INTO function_versions
		(function_id, content_hash, version, snapped_at, source, lines_added, lines_removed)
		VALUES (?, ?, ?, ?, 'index', 0, 0)`)
	if err != nil {
		_ = tx.Rollback()
		return 0, 0, err
	}
	defer stmt.Close()

	inserted, seen := 0, 0
	for rows.Next() {
		var id, hash, version string
		if err := rows.Scan(&id, &hash, &version); err != nil {
			_ = tx.Rollback()
			return 0, 0, err
		}
		seen++
		res, err := stmt.Exec(id, hash, version, now)
		if err != nil {
			_ = tx.Rollback()
			return 0, 0, err
		}
		if n, _ := res.RowsAffected(); n > 0 {
			inserted++
		}
	}
	if err := rows.Err(); err != nil {
		_ = tx.Rollback()
		return 0, 0, err
	}
	if err := tx.Commit(); err != nil {
		return 0, 0, err
	}
	return inserted, seen, nil
}

// versionsSummary returns aggregate stats per function_id from function_versions.
func (d *DB) versionsSummary(limit int) ([]funcVersionSummary, error) {
	rows, err := d.conn.Query(`
		SELECT function_id,
		       COUNT(DISTINCT content_hash) AS versions,
		       MAX(snapped_at)              AS last_snapped_at
		FROM function_versions
		GROUP BY function_id
		ORDER BY versions DESC, last_snapped_at DESC
		LIMIT ?`, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []funcVersionSummary
	for rows.Next() {
		var s funcVersionSummary
		if err := rows.Scan(&s.FunctionID, &s.Versions, &s.LastSnappedAt); err != nil {
			return nil, err
		}
		out = append(out, s)
	}
	return out, rows.Err()
}

type funcVersionSummary struct {
	FunctionID    string
	Versions      int64
	LastSnappedAt int64
}
