package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
	"unicode/utf8"

	"igit.com/xbase/raft/db"
)

const DataDir = "cli_data"

// ANSI Colors
const (
	ColorReset   = "\033[0m"
	ColorRed     = "\033[31m"
	ColorGreen   = "\033[32m"
	ColorYellow  = "\033[33m"
	ColorBlue    = "\033[34m"
	ColorPurple  = "\033[35m"
	ColorCyan    = "\033[36m"
	ColorGray    = "\033[37m"
	ColorBold    = "\033[1m"
)

func main() {
	// Initialize DB
	e, err := db.NewEngine(DataDir)
	if err != nil {
		fmt.Printf("%sError initializing DB: %v%s\n", ColorRed, err, ColorReset)
		os.Exit(1)
	}
	defer e.Close()

	printWelcome()

	// Auto-seed if empty
	res, _ := e.Query("LIMIT 1")
	if len(res) == 0 {
		fmt.Printf("%s[!] Database appears empty. Seeding 1000 records...%s\n", ColorYellow, ColorReset)
		seedData(e)
	} else {
		fmt.Printf("%s[+] Database loaded. Ready for queries.%s\n", ColorGreen, ColorReset)
	}

	scanner := bufio.NewScanner(os.Stdin)

	for {
		fmt.Printf("\n%sraftdb%s> ", ColorBlue, ColorReset)
		if !scanner.Scan() {
			break
		}
		line := scanner.Text()
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		parts := strings.Fields(line)
		cmd := strings.ToLower(parts[0])

		switch cmd {
		case "exit", "quit":
			fmt.Printf("%sBye!%s\n", ColorGreen, ColorReset)
			return
		case "help":
			printHelp()
		case "seed":
			seedData(e)
		case "add":
			handleAdd(e, parts)
		case "count":
			handleCount(e, line)
		default:
			handleQuery(e, line)
		}
	}
}

func handleAdd(e *db.Engine, parts []string) {
	if len(parts) < 3 {
		fmt.Printf("%sUsage: add <key> <value>%s\n", ColorRed, ColorReset)
		return
	}
	key := parts[1]
	val := strings.Join(parts[2:], " ")
	idx := uint64(time.Now().UnixNano())
	
	start := time.Now()
	err := e.Set(key, val, idx)
	duration := time.Since(start)

	if err != nil {
		fmt.Printf("%sError adding data: %v%s\n", ColorRed, err, ColorReset)
	} else {
		fmt.Printf("%sQuery OK, 1 row affected (%v)%s\n", ColorGreen, duration, ColorReset)
	}
}

func handleCount(e *db.Engine, line string) {
	// Format: count key like "..."
	// Remove "count" from start
	query := strings.TrimSpace(line[5:])
	if query == "" {
		fmt.Printf("%sUsage: count <query_conditions>%s\n", ColorRed, ColorReset)
		return
	}

	start := time.Now()
	// Use Query to get results then count
	// Note: If Engine had a Count() method, we would use it here.
	results, err := e.Query(query)
	duration := time.Since(start)

	if err != nil {
		fmt.Printf("%sError: %v%s\n", ColorRed, err, ColorReset)
		return
	}

	fmt.Printf("%s+-------+%s\n", ColorYellow, ColorReset)
	fmt.Printf("%s| COUNT |%s\n", ColorYellow, ColorReset)
	fmt.Printf("%s+-------+%s\n", ColorYellow, ColorReset)
	fmt.Printf("| %-5d |\n", len(results))
	fmt.Printf("%s+-------+%s\n", ColorYellow, ColorReset)
	fmt.Printf("%s1 row in set (%v)%s\n", ColorGreen, duration, ColorReset)
}

func handleQuery(e *db.Engine, query string) {
	start := time.Now()
	results, err := e.Query(query)
	duration := time.Since(start)

	if err != nil {
		fmt.Printf("%sError executing query: %v%s\n", ColorRed, err, ColorReset)
		return
	}

	if len(results) == 0 {
		fmt.Printf("%sEmpty set (%v)%s\n", ColorGray, duration, ColorReset)
		return
	}

	// Calculate column widths
	maxKey := 3
	maxVal := 5
	maxIdx := 12

	for _, r := range results {
		if len(r.Key) > maxKey {
			maxKey = len(r.Key)
		}
		// Truncate value for display if too long
		vLen := utf8.RuneCountInString(r.Value)
		if vLen > 60 {
			vLen = 60
		}
		if vLen > maxVal {
			maxVal = vLen
		}
	}
	if maxKey > 40 { maxKey = 40 } // Hard limit for key display

	// Print Table Header
	printSeparator(maxKey, maxVal, maxIdx)
	fmt.Printf("| %-*s | %-*s | %-*s |\n", maxKey, "KEY", maxVal, "VALUE", maxIdx, "COMMIT_INDEX")
	printSeparator(maxKey, maxVal, maxIdx)

	// Print Rows
	for _, r := range results {
		k := r.Key
		if utf8.RuneCountInString(k) > maxKey {
			k = k[:maxKey-3] + "..."
		}
		v := r.Value
		if utf8.RuneCountInString(v) > maxVal {
			v = v[:maxVal-3] + "..."
		}
		fmt.Printf("| %-*s | %-*s | %-*d |\n", maxKey, k, maxVal, v, maxIdx, r.CommitIndex)
	}
	printSeparator(maxKey, maxVal, maxIdx)
	
	fmt.Printf("%s%d rows in set (%v)%s\n", ColorGreen, len(results), duration, ColorReset)
}

func printSeparator(k, v, i int) {
	fmt.Printf("%s+%s+%s+%s+%s\n", ColorYellow, strings.Repeat("-", k+2), strings.Repeat("-", v+2), strings.Repeat("-", i+2), ColorReset)
}

func seedData(e *db.Engine) {
	fmt.Println("Seeding 1000 records...")
	start := time.Now()
	
	prefixes := []string{"user", "product", "log", "config"}
	
	for i := 0; i < 1000; i++ {
		prefix := prefixes[rand.Intn(len(prefixes))]
		key := fmt.Sprintf("%s:%d", prefix, i)
		
		var val string
		switch prefix {
		case "user":
			val = fmt.Sprintf("name=User%d;role=%s;active=true", i, randomRole())
		case "product":
			val = fmt.Sprintf("title=Item%d;price=%d;desc=%s", i, rand.Intn(1000), randomDesc())
		case "log":
			val = fmt.Sprintf("level=%s;msg=Something happened at %d", randomLevel(), i)
		case "config":
			val = fmt.Sprintf("setting=%d;enabled=%v", i, rand.Intn(2) == 1)
		}

		e.Set(key, val, uint64(i+1))
	}
	
	fmt.Printf("Seeded 1000 records in %v\n", time.Since(start))
}

func randomRole() string {
	roles := []string{"admin", "editor", "viewer", "guest"}
	return roles[rand.Intn(len(roles))]
}

func randomLevel() string {
	levels := []string{"INFO", "WARN", "ERROR", "DEBUG"}
	return levels[rand.Intn(len(levels))]
}

func randomDesc() string {
	adjectives := []string{"Great", "Awesome", "Standard", "Basic", "Premium"}
	nouns := []string{"Widget", "Tool", "Gadget", "Device"}
	return fmt.Sprintf("%s %s", adjectives[rand.Intn(len(adjectives))], nouns[rand.Intn(len(nouns))])
}

func printWelcome() {
	fmt.Printf(`%s
    ____        ______   ____  ____ 
   / __ \____ _/ __/ /_ / __ \/ __ )
  / /_/ / __ '/ /_/ __// / / / __  |
 / _, _/ /_/ / __/ /_ / /_/ / /_/ / 
/_/ |_|\__,_/_/  \__//_____/_____/  
                                    
%sWelcome to RaftDB CLI Monitor.%s
Type 'help' for commands.
`, ColorCyan, ColorBold, ColorReset)
}

func printHelp() {
	fmt.Printf(`
%sCommands:%s
  %shelp%s                     Show this help
  %sseed%s                     Insert 1000 random records
  %sadd <key> <value>%s        Add a new record
  %scount <query>%s            Count records matching query
  %s<query>%s                  Execute a RaftDB query
  %sexit / quit%s              Exit the CLI

%sQuery Examples:%s
  key like "user:*"                    Find all users
  key = "user:10"                      Find specific user
  value like "*admin*"                 Find full-text matches (admin role)
  value like "*ERROR*"                 Find error logs
  key like "product:*" LIMIT 5         List 5 products
  key like "log:*" OFFSET 10 LIMIT 5   Pagination example
  
%sCount Examples:%s
  count key like "user:*"              Count total users
  count value like "*admin*"           Count admins
`, ColorYellow, ColorReset, 
ColorGreen, ColorReset,
ColorGreen, ColorReset,
ColorGreen, ColorReset,
ColorGreen, ColorReset,
ColorGreen, ColorReset,
ColorGreen, ColorReset,
ColorYellow, ColorReset,
ColorYellow, ColorReset)
}
