package e2e

import (
	"database/sql"
	"encoding/json"
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"

	"github.com/cline/cli/pkg/common"
	_ "github.com/mattn/go-sqlite3"
	"google.golang.org/grpc/health/grpc_health_v1"
)

// readInstancesFromSQLite reads instances directly from the SQLite database for testing
func readInstancesFromSQLite(t *testing.T, clineDir string) []common.CoreInstanceInfo {
	t.Helper()

	dbPath := filepath.Join(clineDir, common.SETTINGS_SUBFOLDER, "locks.db")

	// Check if database exists
	if _, err := os.Stat(dbPath); os.IsNotExist(err) {
		return []common.CoreInstanceInfo{}
	}

	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		t.Logf("Warning: Failed to open SQLite database: %v", err)
		return []common.CoreInstanceInfo{}
	}
	defer db.Close()

	// Query instance locks
	query := common.SelectInstanceLockHoldersAscSQL

	rows, err := db.Query(query)
	if err != nil {
		t.Logf("Warning: Failed to query instance locks: %v", err)
		return []common.CoreInstanceInfo{}
	}
	defer rows.Close()

	var instances []common.CoreInstanceInfo
	for rows.Next() {
		var heldBy, lockTarget string
		var lockedAt int64

		err := rows.Scan(&heldBy, &lockTarget, &lockedAt)
		if err != nil {
			t.Logf("Warning: Failed to scan lock row: %v", err)
			continue
		}

		// Create InstanceInfo
		info := common.CoreInstanceInfo{
			Address:            heldBy,
			HostServiceAddress: lockTarget,
			Status:             grpc_health_v1.HealthCheckResponse_UNKNOWN, // Will be updated by health check
			LastSeen:           time.Unix(lockedAt/1000, 0),                // Convert from milliseconds
		}

		instances = append(instances, info)
	}

	return instances
}

// readDefaultInstanceFromSettings reads the default instance from the settings file
func readDefaultInstanceFromSettings(t *testing.T, clineDir string) string {
	t.Helper()

	settingsPath := filepath.Join(clineDir, common.SETTINGS_SUBFOLDER, "settings", "cli-default-instance.json")

	data, err := os.ReadFile(settingsPath)
	if err != nil {
		if os.IsNotExist(err) {
			return ""
		}
		t.Logf("Warning: Failed to read default instance file: %v", err)
		return ""
	}

	var tmp struct {
		DefaultInstance string `json:"default_instance"`
	}
	if err := json.Unmarshal(data, &tmp); err != nil {
		t.Logf("Warning: Failed to parse default instance file: %v", err)
		return ""
	}

	return tmp.DefaultInstance
}

// insertRemoteInstanceIntoSQLite inserts a remote instance entry directly into SQLite for testing
func insertRemoteInstanceIntoSQLite(t *testing.T, dbPath, address string, corePort, hostPort int) error {
	t.Helper()

	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		return err
	}
	defer db.Close()

	// Initialize database schema for testing
	createTableSQL := `
		CREATE TABLE IF NOT EXISTS locks (
			id INTEGER PRIMARY KEY,
			held_by TEXT NOT NULL,
			lock_type TEXT NOT NULL CHECK (lock_type IN ('file', 'instance', 'folder')),
			lock_target TEXT NOT NULL,
			locked_at INTEGER NOT NULL,
			UNIQUE(lock_type, lock_target)
		);
	`
	createIndexesSQL := `
		CREATE INDEX IF NOT EXISTS idx_locks_held_by ON locks(held_by);
		CREATE INDEX IF NOT EXISTS idx_locks_type ON locks(lock_type);
		CREATE INDEX IF NOT EXISTS idx_locks_target ON locks(lock_target);
	`

	if _, err := db.Exec(createTableSQL); err != nil {
		return err
	}
	if _, err := db.Exec(createIndexesSQL); err != nil {
		return err
	}

	// Insert the remote instance
	hostAddress := "remote.example.com:0"
	if hostPort != 0 {
		hostAddress = "remote.example.com:" + strconv.Itoa(hostPort)
	}

	insertSQL := `INSERT INTO locks (held_by, lock_type, lock_target, locked_at) VALUES (?, 'instance', ?, ?)`
	_, err = db.Exec(insertSQL, address, hostAddress, time.Now().Unix()*1000)
	return err
}

// verifyInstanceExistsInSQLite checks if an instance exists in the SQLite database
func verifyInstanceExistsInSQLite(t *testing.T, dbPath, address string) bool {
	t.Helper()

	db, err := sql.Open("sqlite3", dbPath)
	if err != nil {
		t.Logf("Failed to open database: %v", err)
		return false
	}
	defer db.Close()

	query := `SELECT COUNT(*) FROM locks WHERE held_by = ? AND lock_type = 'instance'`
	var count int
	err = db.QueryRow(query, address).Scan(&count)
	if err != nil {
		t.Logf("Failed to query database: %v", err)
		return false
	}

	return count > 0
}
