package database

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

	libsql "github.com/tursodatabase/go-libsql"

	"github.com/tim/cairnquire/apps/server/internal/config"
)

type DB interface {
	SQL() *sql.DB
	Close() error
}

type dbHandle struct {
	sql *sql.DB
}

func Open(ctx context.Context, cfg config.DatabaseConfig) (DB, error) {
	if err := os.MkdirAll(filepath.Dir(cfg.Path), 0o755); err != nil {
		return nil, fmt.Errorf("create database directory: %w", err)
	}

	var (
		db  *sql.DB
		err error
	)
	if cfg.PrimaryURL == "" {
		db, err = sql.Open("libsql", "file:"+cfg.Path)
		if err != nil {
			return nil, fmt.Errorf("open local libsql database: %w", err)
		}
	} else {
		var opts []libsql.Option
		if cfg.AuthToken != "" {
			opts = append(opts, libsql.WithAuthToken(cfg.AuthToken))
		}

		connector, err := libsql.NewEmbeddedReplicaConnector(cfg.Path, cfg.PrimaryURL, opts...)
		if err != nil {
			return nil, fmt.Errorf("create libsql connector: %w", err)
		}

		db = sql.OpenDB(connector)
	}

	db.SetConnMaxLifetime(5 * time.Minute)
	db.SetMaxOpenConns(1)
	db.SetMaxIdleConns(1)

	if err := db.PingContext(ctx); err != nil {
		return nil, fmt.Errorf("ping database: %w", err)
	}

	var journalMode string
	if err := db.QueryRowContext(ctx, "PRAGMA journal_mode=WAL").Scan(&journalMode); err != nil {
		return nil, fmt.Errorf("enable wal mode: %w", err)
	}

	if _, err := db.ExecContext(ctx, "PRAGMA foreign_keys=ON"); err != nil {
		return nil, fmt.Errorf("enable foreign keys: %w", err)
	}

	return &dbHandle{sql: db}, nil
}

func (d *dbHandle) SQL() *sql.DB {
	return d.sql
}

func (d *dbHandle) Close() error {
	return d.sql.Close()
}
