package main

import (
	"fmt"
	"log"
	"time"

	"direct-dev.ru/gitea/GiteaAdmin/elowdb-go/pkg/linedb"
)

// testSingleInsert тестирует вставку одной записи
func testSingleInsert() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "users",
				AllocSize:      256,
				IndexedFields:  []string{"id", "username"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем пользователя
	user := map[string]any{
		"id":        1,
		"username":  "john_doe",
		"email":     "john@example.com",
		"isActive":  true,
		"role":      "user",
		"createdAt": time.Now().Unix(),
	}

	// Вставляем данные
	if err := db.Insert(user, "users", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert user: %v", err)
		return
	}

	// Читаем данные
	users, err := db.Read("users", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read users: %v", err)
		return
	}

	fmt.Printf("   Пользователей в базе: %d\n", len(users))
	if len(users) > 0 {
		if record, ok := users[0].(map[string]any); ok {
			fmt.Printf("   ID: %v, Username: %s\n", record["id"], record["username"])
		}
	}
}

// testArrayInsert тестирует вставку массива записей
func testArrayInsert() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "products",
				AllocSize:      256,
				IndexedFields:  []string{"id", "name"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем массив продуктов
	products := []any{
		map[string]any{
			"id":       1,
			"name":     "Laptop",
			"price":    999.99,
			"category": "Electronics",
			"inStock":  true,
		},
		map[string]any{
			"id":       2,
			"name":     "Mouse",
			"price":    29.99,
			"category": "Electronics",
			"inStock":  true,
		},
		map[string]any{
			"id":       3,
			"name":     "Keyboard",
			"price":    79.99,
			"category": "Electronics",
			"inStock":  false,
		},
	}

	// Вставляем данные
	if err := db.Insert(products, "products", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert products: %v", err)
		return
	}

	// Читаем данные
	productsData, err := db.Read("products", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read products: %v", err)
		return
	}

	fmt.Printf("   Продуктов в базе: %d\n", len(productsData))
	for i, product := range productsData {
		if record, ok := product.(map[string]any); ok {
			fmt.Printf("   %d. ID: %v, Name: %s, Price: %v\n", i+1, record["id"], record["name"], record["price"])
		}
	}
}

// testAutoID тестирует автоматическую генерацию ID
func testAutoID() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "orders",
				AllocSize:      256,
				IndexedFields:  []string{"id", "customerId"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем заказы без ID
	orders := []any{
		map[string]any{
			"customerId": 1,
			"amount":     150.00,
			"status":     "pending",
			"createdAt":  time.Now().Unix(),
		},
		map[string]any{
			"customerId": 2,
			"amount":     75.50,
			"status":     "completed",
			"createdAt":  time.Now().Unix(),
		},
	}

	// Вставляем данные
	if err := db.Insert(orders, "orders", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert orders: %v", err)
		return
	}

	// Читаем данные
	ordersData, err := db.Read("orders", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read orders: %v", err)
		return
	}

	fmt.Printf("   Заказов в базе: %d\n", len(ordersData))
	for i, order := range ordersData {
		if record, ok := order.(map[string]any); ok {
			fmt.Printf("   %d. ID: %v, Customer: %v, Amount: %v\n", i+1, record["id"], record["customerId"], record["amount"])
		}
	}
}

// testPartitionedCollections тестирует партиционированные коллекции
func testPartitionedCollections() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных с партиционированными коллекциями
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "users_2024",
				AllocSize:      256,
				IndexedFields:  []string{"id", "username"},
			},
			{
				CollectionName: "users_2023",
				AllocSize:      256,
				IndexedFields:  []string{"id", "username"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем пользователей для разных партиций
	users2024 := []any{
		map[string]any{
			"id":       1,
			"username": "user_2024_1",
			"email":    "user1@2024.com",
			"year":     2024,
		},
		map[string]any{
			"id":       2,
			"username": "user_2024_2",
			"email":    "user2@2024.com",
			"year":     2024,
		},
	}

	users2023 := []any{
		map[string]any{
			"id":       3,
			"username": "user_2023_1",
			"email":    "user1@2023.com",
			"year":     2023,
		},
	}

	// Вставляем данные в разные партиции
	if err := db.Insert(users2024, "users_2024", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert users 2024: %v", err)
		return
	}

	if err := db.Insert(users2023, "users_2023", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert users 2023: %v", err)
		return
	}

	// Читаем данные из обеих партиций
	users2024Data, err := db.Read("users_2024", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read users 2024: %v", err)
		return
	}

	users2023Data, err := db.Read("users_2023", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read users 2023: %v", err)
		return
	}

	fmt.Printf("   Пользователей 2024: %d\n", len(users2024Data))
	fmt.Printf("   Пользователей 2023: %d\n", len(users2023Data))
}

// testUniquenessCheck тестирует проверку уникальности
func testUniquenessCheck() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "unique_users",
				AllocSize:      256,
				IndexedFields:  []string{"id", "email"},
				UniqueFields:   []string{"email"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем пользователя
	user := map[string]any{
		"id":       1,
		"username": "unique_user",
		"email":    "unique@example.com",
		"isActive": true,
	}

	// Вставляем данные
	if err := db.Insert(user, "unique_users", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert user: %v", err)
		return
	}

	// Пытаемся вставить пользователя с тем же email
	duplicateUser := map[string]any{
		"id":       2,
		"username": "duplicate_user",
		"email":    "unique@example.com", // Тот же email
		"isActive": true,
	}

	if err := db.Insert(duplicateUser, "unique_users", linedb.LineDbAdapterOptions{}); err != nil {
		fmt.Printf("   Ожидаемая ошибка дублирования: %v\n", err)
	} else {
		fmt.Printf("   Дублирование не обнаружено\n")
	}

	// Читаем данные
	users, err := db.Read("unique_users", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read users: %v", err)
		return
	}

	fmt.Printf("   Уникальных пользователей: %d\n", len(users))
}

// testDifferentDataTypes тестирует различные типы данных
func testDifferentDataTypes() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "mixed_data",
				AllocSize:      256,
				IndexedFields:  []string{"id", "type"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем данные разных типов
	mixedData := []any{
		map[string]any{
			"id":       1,
			"type":     "string",
			"value":    "Hello World",
			"isString": true,
		},
		map[string]any{
			"id":       2,
			"type":     "number",
			"value":    42.5,
			"isNumber": true,
		},
		map[string]any{
			"id":     3,
			"type":   "boolean",
			"value":  true,
			"isBool": true,
		},
		map[string]any{
			"id":      4,
			"type":    "array",
			"value":   []any{1, 2, 3, "four"},
			"isArray": true,
		},
		map[string]any{
			"id":       5,
			"type":     "object",
			"value":    map[string]any{"nested": "value", "count": 10},
			"isObject": true,
		},
	}

	// Вставляем данные
	if err := db.Insert(mixedData, "mixed_data", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert mixed data: %v", err)
		return
	}

	// Читаем данные
	data, err := db.Read("mixed_data", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read mixed data: %v", err)
		return
	}

	fmt.Printf("   Записей с разными типами данных: %d\n", len(data))
	for i, record := range data {
		if item, ok := record.(map[string]any); ok {
			fmt.Printf("   %d. ID: %v, Type: %s\n", i+1, item["id"], item["type"])
		}
	}
}

// testBulkInsert тестирует массовую вставку
func testBulkInsert() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 10000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "bulk_items",
				AllocSize:      1024,
				IndexedFields:  []string{"id", "category"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем большое количество записей
	var bulkItems []any
	for i := 1; i <= 1000; i++ {
		item := map[string]any{
			"id":        i,
			"name":      fmt.Sprintf("Item %d", i),
			"category":  fmt.Sprintf("Category %d", (i-1)%10+1),
			"price":     float64(i) * 1.5,
			"inStock":   i%2 == 0,
			"createdAt": time.Now().Unix(),
		}
		bulkItems = append(bulkItems, item)
	}

	// Вставляем данные
	startTime := time.Now()
	if err := db.Insert(bulkItems, "bulk_items", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert bulk items: %v", err)
		return
	}
	insertTime := time.Since(startTime)

	// Читаем данные
	startTime = time.Now()
	items, err := db.Read("bulk_items", linedb.LineDbAdapterOptions{})
	if err != nil {
		log.Printf("Failed to read bulk items: %v", err)
		return
	}
	readTime := time.Since(startTime)

	fmt.Printf("   Массовая вставка: %d записей за %v\n", len(items), insertTime)
	fmt.Printf("   Чтение: %d записей за %v\n", len(items), readTime)
}

// testMultipleCollections тестирует работу с множественными коллекциями
func testMultipleCollections() {
	// Создаем базу данных
	db := linedb.NewLineDb(nil)

	// Инициализируем базу данных с множественными коллекциями
	initOptions := &linedb.LineDbInitOptions{
		CacheSize: 1000,
		CacheTTL:  10 * time.Second,
		DBFolder:  "./data/test-linedb-insert",
		Collections: []linedb.JSONLFileOptions{
			{
				CollectionName: "customers",
				AllocSize:      256,
				IndexedFields:  []string{"id", "email"},
			},
			{
				CollectionName: "orders",
				AllocSize:      256,
				IndexedFields:  []string{"id", "customerId"},
			},
			{
				CollectionName: "products",
				AllocSize:      256,
				IndexedFields:  []string{"id", "name"},
			},
		},
	}

	if err := db.Init(true, initOptions); err != nil {
		log.Printf("Failed to init database: %v", err)
		return
	}
	defer db.Close()

	// Создаем данные для разных коллекций
	customers := []any{
		map[string]any{
			"id":       1,
			"name":     "John Doe",
			"email":    "john@example.com",
			"isActive": true,
		},
		map[string]any{
			"id":       2,
			"name":     "Jane Smith",
			"email":    "jane@example.com",
			"isActive": true,
		},
	}

	orders := []any{
		map[string]any{
			"id":         1,
			"customerId": 1,
			"amount":     150.00,
			"status":     "completed",
		},
		map[string]any{
			"id":         2,
			"customerId": 2,
			"amount":     75.50,
			"status":     "pending",
		},
	}

	products := []any{
		map[string]any{
			"id":       1,
			"name":     "Laptop",
			"price":    999.99,
			"category": "Electronics",
		},
		map[string]any{
			"id":       2,
			"name":     "Mouse",
			"price":    29.99,
			"category": "Electronics",
		},
	}

	// Вставляем данные в разные коллекции
	if err := db.Insert(customers, "customers", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert customers: %v", err)
		return
	}

	if err := db.Insert(orders, "orders", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert orders: %v", err)
		return
	}

	if err := db.Insert(products, "products", linedb.LineDbAdapterOptions{}); err != nil {
		log.Printf("Failed to insert products: %v", err)
		return
	}

	// Читаем данные из всех коллекций
	customersData, _ := db.Read("customers", linedb.LineDbAdapterOptions{})
	ordersData, _ := db.Read("orders", linedb.LineDbAdapterOptions{})
	productsData, _ := db.Read("products", linedb.LineDbAdapterOptions{})

	fmt.Printf("   Коллекций: 3\n")
	fmt.Printf("   Клиентов: %d\n", len(customersData))
	fmt.Printf("   Заказов: %d\n", len(ordersData))
	fmt.Printf("   Продуктов: %d\n", len(productsData))
}
