package handlers

import (
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"git.elijahkuntz.com/Elijah/drive/config"
	"git.elijahkuntz.com/Elijah/drive/database"
)

// CreateVersion checks if a file exists and if so, moves it to the .versions directory
// and records it in the database before it gets overwritten.
// Call this BEFORE writing the new file to disk.
func CreateVersion(db *database.DB, cfg *config.Config, fullPath string, relPath string) error {
	info, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // No existing file, nothing to version
		}
		return err
	}

	if info.IsDir() {
		return nil // Don't version directories
	}

	// Check if versioning is enabled/has a max limit
	val, err := db.GetSetting("max_versions")
	maxVersions := 5
	if err == nil {
		if v, e := strconv.Atoi(val); e == nil {
			maxVersions = v
		}
	}

	if maxVersions <= 0 {
		return nil // Versioning disabled
	}

	// Get current file details from DB (for checksum)
	var checksum string
	err = db.QueryRow("SELECT checksum FROM files WHERE path = ?", filepath.ToSlash(relPath)).Scan(&checksum)
	if err != nil {
		checksum = "" // fallback
	}

	// Generate version path
	timestamp := time.Now().Format("20060102150405")
	versionFileName := fmt.Sprintf("%s_%s%s", strings.TrimSuffix(filepath.Base(relPath), filepath.Ext(relPath)), timestamp, filepath.Ext(relPath))
	versionRelPath := filepath.Join(filepath.Dir(relPath), versionFileName)
	versionFullPath := filepath.Join(cfg.VersionsDir, versionRelPath)

	if err := os.MkdirAll(filepath.Dir(versionFullPath), 0755); err != nil {
		return err
	}

	// Move current file to versions directory
	if err := os.Rename(fullPath, versionFullPath); err != nil {
		return err
	}

	// Determine version number
	var currentMax int
	err = db.QueryRow("SELECT COALESCE(MAX(version_number), 0) FROM file_versions WHERE file_path = ?", filepath.ToSlash(relPath)).Scan(&currentMax)
	if err != nil {
		currentMax = 0
	}
	versionNumber := currentMax + 1

	// Insert version record
	_, err = db.Exec(`
		INSERT INTO file_versions (file_path, version_number, version_path, size, checksum)
		VALUES (?, ?, ?, ?, ?)
	`, filepath.ToSlash(relPath), versionNumber, filepath.ToSlash(versionRelPath), info.Size(), checksum)

	if err != nil {
		return err
	}

	// Prune old versions
	pruneVersions(db, cfg, relPath, maxVersions)

	return nil
}

func pruneVersions(db *database.DB, cfg *config.Config, relPath string, maxVersions int) {
	rows, err := db.Query(`
		SELECT id, version_path FROM file_versions 
		WHERE file_path = ? 
		ORDER BY version_number DESC 
		LIMIT -1 OFFSET ?
	`, filepath.ToSlash(relPath), maxVersions)
	
	if err != nil {
		return
	}
	defer rows.Close()

	var idsToDelete []int
	for rows.Next() {
		var id int
		var vPath string
		if err := rows.Scan(&id, &vPath); err == nil {
			idsToDelete = append(idsToDelete, id)
			os.Remove(filepath.Join(cfg.VersionsDir, filepath.FromSlash(vPath)))
		}
	}

	if len(idsToDelete) > 0 {
		for _, id := range idsToDelete {
			db.Exec("DELETE FROM file_versions WHERE id = ?", id)
		}
	}
}
