package main

import (
	"context"
	"fmt"
	"log"
	"net/url"
	"time"

	"api-service/internal/config"
	"api-service/internal/database"
	"api-service/internal/utils/query"
	"api-service/internal/validation"

	"github.com/jmoiron/sqlx"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

// This file provides comprehensive examples of using the query builder library
// for performing various database operations including CRUD, transactions, joins, etc.
// Each example function demonstrates how to build queries, print them, and execute them.
// =============================================================================
// DEFINISI MODEL (CONTOH)
// =============================================================================

// User adalah contoh struct untuk tabel 'users'.
type User struct {
	ID        int       `db:"id" bson:"_id,omitempty"`
	Name      string    `db:"name" bson:"name"`
	Email     string    `db:"email" bson:"email"`
	Status    string    `db:"status" bson:"status"`
	CreatedAt time.Time `db:"created_at" bson:"created_at"`
}

// Post adalah contoh struct untuk tabel 'posts'.
type Post struct {
	ID        int       `db:"id" bson:"_id,omitempty"`
	UserID    int       `db:"user_id" bson:"user_id"`
	Title     string    `db:"title" bson:"title"`
	Content   string    `db:"content" bson:"content"`
	CreatedAt time.Time `db:"created_at" bson:"created_at"`
}

// Employee adalah contoh struct untuk tabel 'employees' dengan kolom JSON.
type Employee struct {
	ID         int                    `db:"id" bson:"_id,omitempty"`
	Name       string                 `db:"name" bson:"name"`
	Department string                 `db:"department" bson:"department"`
	Salary     float64                `db:"salary" bson:"salary"`
	Metadata   map[string]interface{} `db:"metadata" bson:"metadata"` // Kolom JSON/JSONB
}

// =============================================================================
// FUNGSI UTAMA
// =============================================================================

func main() {
	cfg := setupConfig()
	dbService := database.New(cfg)

	fmt.Println("============================================================")
	fmt.Println("         CONTOH 1: QUERY DASAR (SELECT, INSERT, UPDATE, DELETE)")
	fmt.Println("============================================================")
	basicCRUDExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 2: TRANSAKSI SQL (POSTGRESQL)")
	fmt.Println("============================================================")
	sqlTransactionExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 3: TRANSAKSI MONGODB")
	fmt.Println("============================================================")
	mongoTransactionExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 4: QUERY DENGAN FILTER DAN PAGINASI")
	fmt.Println("============================================================")
	filterAndPaginationExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 5: QUERY DENGAN JOIN")
	fmt.Println("============================================================")
	joinExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 6: QUERY DENGAN CTE (COMMON TABLE EXPRESSION)")
	fmt.Println("============================================================")
	cteExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 7: QUERY DENGAN WINDOW FUNCTION")
	fmt.Println("============================================================")
	windowFunctionExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 8: VALIDASI DATA DINAMIS")
	fmt.Println("============================================================")
	validationExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 9: OPERASI JSON")
	fmt.Println("============================================================")
	jsonQueryExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 10: QUERY MONGODB (CRUD & AGGREGATION)")
	fmt.Println("============================================================")
	mongodbExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 11: PENGGUNAAN READ REPLICA")
	fmt.Println("============================================================")
	readReplicaExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 12: HEALTH CHECK DATABASE")
	fmt.Println("============================================================")
	healthCheckExample(dbService)

	fmt.Println("\n============================================================")
	fmt.Println("         CONTOH 13: PARSING QUERY DARI URL")
	fmt.Println("============================================================")
	urlQueryParsingExample(dbService)
}

func setupConfig() *config.Config {
	return &config.Config{
		Databases: map[string]config.DatabaseConfig{
			"main": {
				Type:            "postgres",
				Host:            "localhost",
				Port:            5432,
				Username:        "user",
				Password:        "password",
				Database:        "company_db",
				SSLMode:         "disable",
				MaxOpenConns:    25,
				MaxIdleConns:    5,
				ConnMaxLifetime: time.Hour,
			},
		},
		"mongodb": config.DatabaseConfig{
			Type:     "mongodb",
			Host:     "localhost",
			Port:     27017,
			Database: "company_db",
			Username: "user",
			Password: "password",
		},
	}
}

// =============================================================================
// CONTOH 1: QUERY DASAR (CRUD)
// =============================================================================

// basicCRUDExample demonstrates basic Create, Read, Update, Delete operations using the query builder.
// It shows how to build SQL queries, print them, and execute them while displaying results.
// Expected output: Prints INSERT SQL and result (new ID), SELECT SQL and user data, UPDATE SQL and affected rows, DELETE SQL and affected rows.
// Example raw queries:
// INSERT: INSERT INTO users (name, email, status) VALUES ($1, $2, $3) RETURNING id
// SELECT: SELECT * FROM users WHERE id = $1
// UPDATE: UPDATE users SET status = $1 WHERE id = $2
// DELETE: DELETE FROM users WHERE id = $1
func basicCRUDExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	// --- INSERT ---
	fmt.Println("\n--- Operasi INSERT ---")
	insertData := query.InsertData{
		Columns: []string{"name", "email", "status"},
		Values:  []interface{}{"Alice", "alice@example.com", "active"},
	}
	sql, args, err := qb.BuildInsertQuery("users", insertData, "id")
	if err != nil {
		log.Printf("Error building INSERT: %v", err)
		return
	}
	fmt.Printf("Generated INSERT SQL: %s\nArgs: %v\n", sql, args)
	result, err := qb.ExecuteInsert(ctx, db, "users", insertData, "id")
	if err != nil {
		log.Printf("Error INSERT: %v", err)
		return
	}
	newID, _ := result.LastInsertId()
	fmt.Printf("-> INSERT: Berhasil menambah user dengan ID: %d\n", newID)

	// --- SELECT (Single Row) ---
	fmt.Println("\n--- Operasi SELECT ---")
	var user User
	selectQuery := query.DynamicQuery{
		Fields: []query.SelectField{{Expression: "*"}},
		From:   "users",
		Filters: []query.FilterGroup{{
			Filters: []query.DynamicFilter{{Column: "id", Operator: query.OpEqual, Value: newID}},
		}},
	}
	sql, args, err = qb.BuildQuery(selectQuery)
	if err != nil {
		log.Printf("Error building SELECT: %v", err)
		return
	}
	fmt.Printf("Generated SELECT SQL: %s\nArgs: %v\n", sql, args)
	err = qb.ExecuteQueryRow(ctx, db, selectQuery, &user)
	if err != nil {
		log.Printf("Error SELECT single row: %v", err)
		return
	}
	fmt.Printf("-> SELECT (Single Row): Berhasil mengambil user: %+v\n", user)

	// --- UPDATE ---
	fmt.Println("\n--- Operasi UPDATE ---")
	updateData := query.UpdateData{
		Columns: []string{"status"},
		Values:  []interface{}{"inactive"},
	}
	updateFilter := []query.FilterGroup{{
		Filters: []query.DynamicFilter{{Column: "id", Operator: query.OpEqual, Value: newID}},
	}}
	sql, args, err = qb.BuildUpdateQuery("users", updateData, updateFilter)
	if err != nil {
		log.Printf("Error building UPDATE: %v", err)
		return
	}
	fmt.Printf("Generated UPDATE SQL: %s\nArgs: %v\n", sql, args)
	_, err = qb.ExecuteUpdate(ctx, db, "users", updateData, updateFilter)
	if err != nil {
		log.Printf("Error UPDATE: %v", err)
		return
	}
	fmt.Printf("-> UPDATE: Berhasil memperbarui status user dengan ID: %d\n", newID)

	// --- DELETE ---
	fmt.Println("\n--- Operasi DELETE ---")
	deleteFilter := []query.FilterGroup{{
		Filters: []query.DynamicFilter{{Column: "id", Operator: query.OpEqual, Value: newID}},
	}}
	sql, args, err = qb.BuildDeleteQuery("users", deleteFilter)
	if err != nil {
		log.Printf("Error building DELETE: %v", err)
		return
	}
	fmt.Printf("Generated DELETE SQL: %s\nArgs: %v\n", sql, args)
	_, err = qb.ExecuteDelete(ctx, db, "users", deleteFilter)
	if err != nil {
		log.Printf("Error DELETE: %v", err)
		return
	}
	fmt.Printf("-> DELETE: Berhasil menghapus user dengan ID: %d\n", newID)
}

// =============================================================================
// CONTOH 2: TRANSAKSI SQL (POSTGRESQL)
// =============================================================================

// sqlTransactionExample demonstrates how to perform atomic transactions involving updates
// across multiple tables using the Query Builder. It builds and prints SQL queries before execution.
// Expected output: Prints UPDATE SQL for salaries and employees, transaction commit/rollback status, and validation results.
// Example raw queries:
// UPDATE salaries: UPDATE salaries SET salary = $1 WHERE employee_id = $2
// UPDATE employees: UPDATE employees SET last_name = $1 WHERE employee_id = $2
func sqlTransactionExample(dbService database.Service) {
	ctx := context.Background()
	employeeID := 123
	newSalary := 75000
	newLastName := "Doe"

	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Fatalf("Gagal mendapatkan koneksi database SQL: %v", err)
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	tx, err := db.BeginTxx(ctx, nil)
	if err != nil {
		log.Fatalf("Gagal memulai transaksi SQL: %v", err)
	}

	defer func() {
		if p := recover(); p != nil {
			fmt.Println("Terjadi panic, melakukan rollback transaksi...")
			_ = tx.Rollback()
			panic(p)
		} else if err != nil {
			fmt.Printf("Transaksi dibatalkan (ROLLBACK) karena error: %v\n", err)
			_ = tx.Rollback()
		} else {
			fmt.Println("Tidak ada error, melakukan COMMIT transaksi...")
			err = tx.Commit()
			if err != nil {
				log.Printf("Gagal melakukan COMMIT transaksi: %v", err)
			}
		}
	}()

	fmt.Printf("Memulai transaksi untuk employee_id: %d\n", employeeID)

	// --- Operasi 1: Update gaji di tabel 'salaries' ---
	fmt.Println("\n--- Operasi 1: UPDATE salaries ---")
	salariesUpdateData := query.UpdateData{
		Columns: []string{"salary"},
		Values:  []interface{}{newSalary},
	}
	salariesFilter := []query.FilterGroup{
		{
			Filters: []query.DynamicFilter{
				{Column: "employee_id", Operator: query.OpEqual, Value: employeeID},
			},
		},
	}
	sql, args, err := qb.BuildUpdateQuery("salaries", salariesUpdateData, salariesFilter)
	if err != nil {
		log.Printf("Error building UPDATE salaries: %v", err)
		return
	}
	fmt.Printf("Generated UPDATE salaries SQL: %s\nArgs: %v\n", sql, args)
	salariesResult, err := qb.ExecuteUpdate(ctx, tx, "salaries", salariesUpdateData, salariesFilter)
	if err != nil {
		return
	}
	salariesRowsAffected, _ := salariesResult.RowsAffected()
	fmt.Printf("-> UPDATE salaries: %d baris terpengaruh.\n", salariesRowsAffected)

	// --- Operasi 2: Update informasi di tabel 'employees' ---
	fmt.Println("\n--- Operasi 2: UPDATE employees ---")
	employeesUpdateData := query.UpdateData{
		Columns: []string{"last_name"},
		Values:  []interface{}{newLastName},
	}
	employeesFilter := []query.FilterGroup{
		{
			Filters: []query.DynamicFilter{
				{Column: "employee_id", Operator: query.OpEqual, Value: employeeID},
			},
		},
	}
	sql, args, err = qb.BuildUpdateQuery("employees", employeesUpdateData, employeesFilter)
	if err != nil {
		log.Printf("Error building UPDATE employees: %v", err)
		return
	}
	fmt.Printf("Generated UPDATE employees SQL: %s\nArgs: %v\n", sql, args)
	employeesResult, err := qb.ExecuteUpdate(ctx, tx, "employees", employeesUpdateData, employeesFilter)
	if err != nil {
		return
	}
	employeesRowsAffected, _ := employeesResult.RowsAffected()
	fmt.Printf("-> UPDATE employees: %d baris terpengaruh.\n", employeesRowsAffected)

	// --- Validasi Akhir Transaksi ---
	if salariesRowsAffected == 1 && employeesRowsAffected == 1 {
		fmt.Println("-> Validasi BERHASIL: Kedua tabel berhasil diperbarui.")
	} else {
		err = fmt.Errorf("validasi GAGAL: diharapkan 1 baris terupdate di setiap tabel, tetapi mendapat %d (salaries) dan %d (employees)", salariesRowsAffected, employeesRowsAffected)
		return
	}
}

// =============================================================================
// CONTOH 3: TRANSAKSI MONGODB
// =============================================================================

// mongoTransactionExample demonstrates MongoDB transactions using the query builder.
// It prints the filters and update operations before executing them in a transaction.
// Expected output: Prints MongoDB filters and update operations for salaries and employees, transaction commit/abort status, and validation results.
// Example raw queries:
// MongoDB filters: {"employee_id": 123}
// MongoDB updates: {"$set": {"salary": 75000}}, {"$set": {"last_name": "Doe"}}
func mongoTransactionExample(dbService database.Service) {
	ctx := context.Background()
	employeeID := 123
	newSalary := 75000
	newLastName := "Doe"

	client, err := dbService.GetMongoClient("mongodb")
	if err != nil {
		log.Fatalf("Gagal mendapatkan klien MongoDB: %v", err)
	}

	salariesCollection := client.Database("company_db").Collection("salaries")
	employeesCollection := client.Database("company_db").Collection("employees")

	session, err := client.StartSession()
	if err != nil {
		log.Fatalf("Gagal memulai sesi MongoDB: %v", err)
	}
	defer session.EndSession(ctx)

	fmt.Printf("Memulai transaksi MongoDB untuk employee_id: %d\n", employeeID)

	_, err = session.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		// --- Operasi 1: Update gaji di koleksi 'salaries' ---
		fmt.Println("\n--- Operasi 1: UPDATE salaries ---")
		salariesFilter := bson.M{"employee_id": employeeID}
		salariesUpdate := bson.M{"$set": bson.M{"salary": newSalary}}
		fmt.Printf("-> MongoDB Update Salaries Filter: %#v\n", salariesFilter)
		fmt.Printf("-> MongoDB Update Salaries Operation: %#v\n", salariesUpdate)

		salariesResult, err := salariesCollection.UpdateOne(sessCtx, salariesFilter, salariesUpdate)
		if err != nil {
			return nil, fmt.Errorf("gagal update koleksi salaries: %w", err)
		}
		fmt.Printf("-> UPDATE salaries: %d dokumen cocok (matched).\n", salariesResult.MatchedCount)

		// --- Operasi 2: Update informasi di koleksi 'employees' ---
		fmt.Println("\n--- Operasi 2: UPDATE employees ---")
		employeesFilter := bson.M{"employee_id": employeeID}
		employeesUpdate := bson.M{"$set": bson.M{"last_name": newLastName}}
		fmt.Printf("-> MongoDB Update Employees Filter: %#v\n", employeesFilter)
		fmt.Printf("-> MongoDB Update Employees Operation: %#v\n", employeesUpdate)

		employeesResult, err := employeesCollection.UpdateOne(sessCtx, employeesFilter, employeesUpdate)
		if err != nil {
			return nil, fmt.Errorf("gagal update koleksi employees: %w", err)
		}
		fmt.Printf("-> UPDATE employees: %d dokumen cocok (matched).\n", employeesResult.MatchedCount)

		// --- Validasi Akhir Transaksi ---
		if salariesResult.MatchedCount == 1 && employeesResult.MatchedCount == 1 {
			fmt.Println("-> Validasi BERHASIL: Kedua koleksi berhasil diperbarui.")
			return nil, nil
		}

		return nil, fmt.Errorf("validasi GAGAL: diharapkan 1 dokumen terupdate di setiap koleksi, tetapi mendapat %d (salaries) dan %d (employees)", salariesResult.MatchedCount, employeesResult.MatchedCount)
	})

	if err != nil {
		fmt.Printf("Transaksi MongoDB dibatalkan (ABORT) karena error: %v\n", err)
	} else {
		fmt.Println("Transaksi MongoDB berhasil di-commit.")
	}
}

// =============================================================================
// CONTOH 4: FILTER DAN PAGINASI
// =============================================================================

// filterAndPaginationExample demonstrates querying with filters and pagination.
// It builds and prints the SELECT query before executing it.
// Expected output: Prints SELECT SQL with filters and pagination, and the number of active users found.
// Example raw query:
// SELECT id, name FROM users WHERE (status = $1 AND created_at > $2) ORDER BY name ASC LIMIT 5 OFFSET 10
func filterAndPaginationExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	query := query.DynamicQuery{
		Fields: []query.SelectField{
			{Expression: "id"},
			{Expression: "name"},
		},
		From: "users",
		Filters: []query.FilterGroup{
			{
				LogicOp: "AND",
				Filters: []query.DynamicFilter{
					{Column: "status", Operator: query.OpEqual, Value: "active"},
					{Column: "created_at", Operator: query.OpGreaterThan, Value: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)},
				},
			},
		},
		Sort:   []query.SortField{{Column: "name", Order: "ASC"}},
		Limit:  5,
		Offset: 10,
	}

	var users []User
	sql, args, err := qb.BuildQuery(query)
	if err != nil {
		log.Printf("Error building SELECT: %v", err)
		return
	}
	fmt.Printf("Generated SELECT SQL: %s\nArgs: %v\n", sql, args)
	err = qb.ExecuteQuery(ctx, db, query, &users)
	if err != nil {
		log.Printf("Error query dengan filter: %v", err)
		return
	}
	fmt.Printf("-> Filter & Paginasi: Ditemukan %d user aktif (halaman 3).\n", len(users))
}

// =============================================================================
// CONTOH 5: QUERY DENGAN JOIN
// =============================================================================

// joinExample demonstrates querying with JOIN operations.
// It builds and prints the JOIN query before executing it.
// Expected output: Prints JOIN SQL query and the number of posts with author names found.
// Example raw query:
// SELECT p.id AS post_id, p.title, u.name AS author_name FROM posts p INNER JOIN users u ON p.user_id = u.id LIMIT 10
func joinExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	query := query.DynamicQuery{
		Fields: []query.SelectField{
			{Expression: "p.id", Alias: "post_id"},
			{Expression: "p.title"},
			{Expression: "u.name", Alias: "author_name"},
		},
		From:    "posts",
		Aliases: "p",
		Joins: []query.Join{
			{
				Type:  "INNER",
				Table: "users",
				Alias: "u",
				OnConditions: query.FilterGroup{
					Filters: []query.DynamicFilter{
						{Column: "p.user_id", Operator: query.OpEqual, Value: "u.id"},
					},
				},
			},
		},
		Limit: 10,
	}

	var results []struct {
		PostID     int    `db:"post_id"`
		Title      string `db:"title"`
		AuthorName string `db:"author_name"`
	}
	sql, args, err := qb.BuildQuery(query)
	if err != nil {
		log.Printf("Error building JOIN: %v", err)
		return
	}
	fmt.Printf("Generated JOIN SQL: %s\nArgs: %v\n", sql, args)
	err = qb.ExecuteQuery(ctx, db, query, &results)
	if err != nil {
		log.Printf("Error query JOIN: %v", err)
		return
	}
	fmt.Printf("-> JOIN: Ditemukan %d post dengan nama penulis.\n", len(results))
}

// =============================================================================
// CONTOH 6: QUERY DENGAN CTE
// =============================================================================

// cteExample demonstrates querying with Common Table Expressions (CTE).
// It builds and prints the CTE query before executing it.
// Expected output: Prints CTE SQL query and the number of users with more than 5 posts.
func cteExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	query := query.DynamicQuery{
		CTEs: []query.CTE{
			{
				Name: "user_post_counts",
				Query: query.DynamicQuery{
					Fields: []query.SelectField{
						{Expression: "user_id"},
						{Expression: "COUNT(*)", Alias: "post_count"},
					},
					From:    "posts",
					GroupBy: []string{"user_id"},
				},
			},
		},
		Fields: []query.SelectField{
			{Expression: "u.name"},
			{Expression: "upc.post_count"},
		},
		From: "users u",
		Joins: []query.Join{
			{
				Type:  "INNER",
				Table: "user_post_counts",
				Alias: "upc",
				OnConditions: query.FilterGroup{
					Filters: []query.DynamicFilter{
						{Column: "u.id", Operator: query.OpEqual, Value: "upc.user_id"},
					},
				},
			},
		},
		Filters: []query.FilterGroup{
			{
				Filters: []query.DynamicFilter{
					{Column: "upc.post_count", Operator: query.OpGreaterThan, Value: 5},
				},
			},
		},
	}

	var results []struct {
		Name      string `db:"name"`
		PostCount int    `db:"post_count"`
	}
	sql, args, err := qb.BuildQuery(query)
	if err != nil {
		log.Printf("Error building CTE: %v", err)
		return
	}
	fmt.Printf("Generated CTE SQL: %s\nArgs: %v\n", sql, args)
	err = qb.ExecuteQuery(ctx, db, query, &results)
	if err != nil {
		log.Printf("Error query CTE: %v", err)
		return
	}
	fmt.Printf("-> CTE: Ditemukan %d user dengan lebih dari 5 post.\n", len(results))
}

// =============================================================================
// CONTOH 7: WINDOW FUNCTION
// =============================================================================

// windowFunctionExample demonstrates querying with window functions.
// It builds and prints the window function query before executing it.
// Expected output: Prints window function SQL query and the number of employees with salary rankings.
func windowFunctionExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	query := query.DynamicQuery{
		Fields: []query.SelectField{
			{Expression: "name"},
			{Expression: "department"},
			{Expression: "salary"},
		},
		From: "employees",
		WindowFunctions: []query.WindowFunction{
			{
				Function: "RANK",
				Over:     "department",
				OrderBy:  "salary DESC",
				Alias:    "salary_rank",
			},
		},
		Filters: []query.FilterGroup{
			{
				Filters: []query.DynamicFilter{
					{Column: "department", Operator: query.OpEqual, Value: "Engineering"},
				},
			},
		},
	}

	var results []struct {
		Name       string  `db:"name"`
		Department string  `db:"department"`
		Salary     float64 `db:"salary"`
		SalaryRank int     `db:"salary_rank"`
	}
	sql, args, err := qb.BuildQuery(query)
	if err != nil {
		log.Printf("Error building Window Function: %v", err)
		return
	}
	fmt.Printf("Generated Window Function SQL: %s\nArgs: %v\n", sql, args)
	err = qb.ExecuteQuery(ctx, db, query, &results)
	if err != nil {
		log.Printf("Error query Window Function: %v", err)
		return
	}
	fmt.Printf("-> Window Function: Ditemukan %d employee di departemen Engineering dengan peringkat gaji.\n", len(results))
}

// =============================================================================
// CONTOH 8: VALIDASI DATA DINAMIS
// =============================================================================

// validationExample demonstrates dynamic data validation using the query builder.
// It builds and prints the validation query before executing it.
// Expected output: Prints validation SQL query and whether the email is duplicate or available.
func validationExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)
	validator := validation.NewDynamicValidator(qb)

	userData := map[string]interface{}{"email": "test@example.com"}
	emailRule := validation.NewUniqueFieldRule("users", "email")

	// Build and print the validation query
	countQuery := query.DynamicQuery{
		From: "users",
		Filters: []query.FilterGroup{{
			Filters: []query.DynamicFilter{{Column: "email", Operator: query.OpEqual, Value: "test@example.com"}},
		}},
	}
	sql, args, err := qb.BuildCountQuery(countQuery)
	if err != nil {
		log.Printf("Error building validation query: %v", err)
		return
	}
	fmt.Printf("Generated Validation SQL: %s\nArgs: %v\n", sql, args)

	isDuplicate, err := validator.Validate(ctx, db, emailRule, userData)
	if err != nil {
		log.Printf("Error validasi: %v", err)
		return
	}

	if isDuplicate {
		fmt.Println("-> Validasi: Email 'test@example.com' sudah ada.")
	} else {
		fmt.Println("-> Validasi: Email 'test@example.com' tersedia.")
	}
}

// =============================================================================
// CONTOH 9: OPERASI JSON
// =============================================================================

// jsonQueryExample demonstrates JSON operations in queries.
// It builds and prints the JSON queries before executing them.
// Expected output: Prints JSON SELECT and UPDATE SQL queries, number of employees found, and update success message.
func jsonQueryExample(dbService database.Service) {
	ctx := context.Background()
	db, err := dbService.GetSQLXDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan koneksi DB: %v", err)
		return
	}
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	query := query.DynamicQuery{
		Fields: []query.SelectField{{Expression: "*"}},
		From:   "employees",
		Filters: []query.FilterGroup{{
			Filters: []query.DynamicFilter{
				{
					Column:   "metadata",
					Operator: query.OpJsonEqual,
					Value:    "Engineering",
					Options:  map[string]interface{}{"path": "department"},
				},
			},
		}},
	}

	var employees []Employee
	sql, args, err := qb.BuildQuery(query)
	if err != nil {
		log.Printf("Error building JSON query: %v", err)
		return
	}
	fmt.Printf("Generated JSON SELECT SQL: %s\nArgs: %v\n", sql, args)
	err = qb.ExecuteQuery(ctx, db, query, &employees)
	if err != nil {
		log.Printf("Error query JSON: %v", err)
		return
	}
	fmt.Printf("-> Operasi JSON: Ditemukan %d employee di departemen Engineering (dari metadata JSON).\n", len(employees))

	updateData := query.UpdateData{
		JsonUpdates: map[string]query.JsonUpdate{
			"metadata": {Path: "role", Value: "Senior Developer"},
		},
	}
	filter := []query.FilterGroup{{Filters: []query.DynamicFilter{{Column: "id", Operator: query.OpEqual, Value: 1}}}}
	sql, args, err = qb.BuildUpdateQuery("employees", updateData, filter)
	if err != nil {
		log.Printf("Error building JSON update: %v", err)
		return
	}
	fmt.Printf("Generated JSON UPDATE SQL: %s\nArgs: %v\n", sql, args)
	_, err = qb.ExecuteUpdate(ctx, db, "employees", updateData, filter)
	if err != nil {
		log.Printf("Error update JSON: %v", err)
		return
	}
	fmt.Println("-> Operasi JSON: Berhasil memperbarui 'role' di metadata untuk employee ID 1.")
}

// =============================================================================
// CONTOH 10: QUERY MONGODB
// =============================================================================

// mongodbExample demonstrates MongoDB queries using the query builder.
// It prints the built filters and pipelines before executing them.
// Expected output: Prints MongoDB find filter, number of active users, aggregation pipeline, and number of departments.
func mongodbExample(dbService database.Service) {
	ctx := context.Background()
	client, err := dbService.GetMongoClient("mongodb")
	if err != nil {
		log.Printf("Gagal mendapatkan klien MongoDB: %v", err)
		return
	}
	collection := client.Database("company_db").Collection("users")
	mqb := query.NewMongoQueryBuilder()

	// --- FIND ---
	fmt.Println("\n--- Operasi FIND ---")
	findQuery := query.DynamicQuery{
		Filters: []query.FilterGroup{{Filters: []query.DynamicFilter{{Column: "status", Operator: query.OpEqual, Value: "active"}}}},
		Limit:   5,
	}
	filter, _, _ := mqb.BuildFindQuery(findQuery)
	fmt.Printf("-> MongoDB Find Filter: %#v\n", filter)

	var users []User
	err = mqb.ExecuteFind(ctx, collection, findQuery, &users)
	if err != nil {
		log.Printf("Error MongoDB Find: %v", err)
		return
	}
	fmt.Printf("-> MongoDB Find: Ditemukan %d user aktif.\n", len(users))

	// --- AGGREGATION ---
	fmt.Println("\n--- Operasi AGGREGATION ---")
	aggQuery := query.DynamicQuery{
		Fields: []query.SelectField{
			{Expression: "department", Alias: "_id"},
			{Expression: "COUNT(*)", Alias: "count"},
		},
		GroupBy: []string{"department"},
	}
	pipeline, _ := mqb.BuildAggregateQuery(aggQuery)
	fmt.Printf("-> MongoDB Aggregation Pipeline: %#v\n", pipeline)

	var aggResults []struct {
		ID    string `bson:"_id"`
		Count int    `bson:"count"`
	}
	err = mqb.ExecuteAggregate(ctx, collection, aggQuery, &aggResults)
	if err != nil {
		log.Printf("Error MongoDB Aggregate: %v", err)
		return
	}
	fmt.Printf("-> MongoDB Aggregate: Ditemukan user di %d departemen.\n", len(aggResults))
}

// =============================================================================
// CONTOH 11: PENGGUNAAN READ REPLICA
// =============================================================================

// readReplicaExample demonstrates using read replicas for queries.
// It builds and prints the count query before executing it on the read replica.
// Expected output: Prints COUNT SQL query and the total number of users from the read replica.
// Example raw query:
// SELECT COUNT(*) FROM users
func readReplicaExample(dbService database.Service) {
	ctx := context.Background()
	readDB, err := dbService.GetReadDB("main")
	if err != nil {
		log.Printf("Gagal mendapatkan read replica: %v", err)
		return
	}
	readxDB := sqlx.NewDb(readDB, "pgx")
	qb := query.NewQueryBuilder(query.DBTypePostgreSQL)

	countQuery := query.DynamicQuery{From: "users"}
	sql, args, err := qb.BuildCountQuery(countQuery)
	if err != nil {
		log.Printf("Error building count query: %v", err)
		return
	}
	fmt.Printf("Generated COUNT SQL: %s\nArgs: %v\n", sql, args)
	count, err := qb.ExecuteCount(ctx, readxDB, countQuery)
	if err != nil {
		log.Printf("Error query di read replica: %v", err)
		return
	}
	fmt.Printf("-> Read Replica: Total user (dari read replica): %d\n", count)
}

// =============================================================================
// CONTOH 12: HEALTH CHECK DATABASE
// =============================================================================

// healthCheckExample demonstrates database health checks.
// It prints the health status of all databases.
// Expected output: Prints health status for each database (up/down with type or error).
func healthCheckExample(dbService database.Service) {
	healthStatus := dbService.Health()
	fmt.Println("-> Health Check Status:")
	for dbName, status := range healthStatus {
		if status["status"] == "up" {
			fmt.Printf("  - Database %s: SEHAT (%s)\n", dbName, status["type"])
		} else {
			fmt.Printf("  - Database %s: TIDAK SEHAT - %s\n", dbName, status["error"])
		}
	}
}

// =============================================================================
// CONTOH 13: PARSING QUERY DARI URL
// =============================================================================

// urlQueryParsingExample demonstrates parsing query parameters from URL.
// It parses the URL query and prints the resulting dynamic query structure.
// Expected output: Prints parsed fields, filters, sort, and limit from the URL query.
func urlQueryParsingExample(dbService database.Service) {
	values := url.Values{}
	values.Set("fields", "id,name")
	values.Set("filter[status][_eq]", "active")
	values.Set("filter[age][_gt]", "25")
	values.Set("sort", "-name")
	values.Set("limit", "10")

	parser := query.NewQueryParser()
	dynamicQuery, err := parser.ParseQuery(values, "users")
	if err != nil {
		log.Printf("Error parsing URL query: %v", err)
		return
	}

	fmt.Println("-> Parsing URL Query:")
	fmt.Printf("  Fields: %v\n", dynamicQuery.Fields)
	fmt.Printf("  Filters: %+v\n", dynamicQuery.Filters)
	fmt.Printf("  Sort: %+v\n", dynamicQuery.Sort)
	fmt.Printf("  Limit: %d\n", dynamicQuery.Limit)
}

// =============================================================================
// AKHIR FILE
// =============================================================================
