//go:build !no_duckdb

package db

import (
	"database/sql"
	"fmt"
	"os"
	"path/filepath"

	_ "github.com/marcboeker/go-duckdb/v2"
)

// duckdbDriverName is the database/sql driver registered by go-duckdb/v2.
const duckdbDriverName = "duckdb"

// DuckDBSchema is the embedded DuckDB schema applied on first open. Phase 0
// creates the analytical snapshot tables empty; later phases populate them.
//
// Kept as a Go string rather than a SQL file under /migrations because DuckDB
// migrations are versioned separately from SQLite migrations (DuckDB doesn't
// share the schema_migrations row store) and the schema for Phase 0 is tiny.
const DuckDBSchema = `
CREATE TABLE IF NOT EXISTS ratio_snapshots (
    id                          BIGINT,
    tracker_id                  TEXT NOT NULL,
    timestamp                   BIGINT NOT NULL,
    simulation_id               BIGINT,
    real_uploaded_bytes         BIGINT,
    real_downloaded_bytes       BIGINT,
    real_ratio                  DOUBLE,
    displayed_uploaded_bytes    BIGINT,
    displayed_downloaded_bytes  BIGINT,
    displayed_ratio             DOUBLE,
    bonus_points                BIGINT,
    unsat_count                 INTEGER,
    unsat_limit                 INTEGER,
    class_or_rank               TEXT,
    raw_json                    TEXT
);

CREATE TABLE IF NOT EXISTS torrent_snapshots (
    id                  BIGINT,
    info_hash           TEXT NOT NULL,
    client_id           TEXT NOT NULL,
    timestamp           BIGINT NOT NULL,
    simulation_id       BIGINT,
    uploaded_bytes      BIGINT,
    downloaded_bytes    BIGINT,
    state               TEXT,
    ratio               DOUBLE,
    seeders             INTEGER,
    leechers            INTEGER,
    upload_speed_bps    BIGINT,
    download_speed_bps  BIGINT
);
`

// OpenDuckDB opens (or creates) the analytical store at path and applies the
// Phase 0 schema if the tables are missing. The directory is created when
// absent.
func OpenDuckDB(path string) (*sql.DB, error) {
	if dir := filepath.Dir(path); dir != "" {
		if err := os.MkdirAll(dir, 0o755); err != nil {
			return nil, fmt.Errorf("duckdb: mkdir %s: %w", dir, err)
		}
	}
	db, err := sql.Open(duckdbDriverName, path)
	if err != nil {
		return nil, fmt.Errorf("duckdb: open: %w", err)
	}
	if err := db.Ping(); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("duckdb: ping: %w", err)
	}
	if _, err := db.Exec(DuckDBSchema); err != nil {
		_ = db.Close()
		return nil, fmt.Errorf("duckdb: apply schema: %w", err)
	}
	return db, nil
}

// DuckDBAvailable reports whether the DuckDB driver is compiled into this
// binary. Always true when the default build tag set is used; the stub build
// (-tags no_duckdb) returns false.
func DuckDBAvailable() bool { return true }
