package sync

import (
	"log"
	"os"
	"path/filepath"
	"sheetless-server/database"
	"sheetless-server/handlers"
	"sheetless-server/models"
	"sheetless-server/utils"
	"time"
)

const uploadDir = "./uploads"

func SyncSheets() error {
	// Get all sheets
	var sheets []models.Sheet
	if err := database.DB.Find(&sheets).Error; err != nil {
		return err
	}

	// Maps
	pathsInDb := make(map[string]*models.Sheet)
	hashToSheets := make(map[uint64][]*models.Sheet)
	for i := range sheets {
		sheet := &sheets[i]
		pathsInDb[sheet.FilePath] = sheet
		hashToSheets[sheet.FileHash] = append(hashToSheets[sheet.FileHash], sheet)
	}

	// Walk uploads dir
	files, err := os.ReadDir(uploadDir)
	if err != nil {
		return err
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		filePath := filepath.Join(uploadDir, file.Name())
		hash, err := utils.FileHash(filePath)
		if err != nil {
			log.Printf("Error hashing file %s: %v", filePath, err)
			continue
		}
		info, err := file.Info()
		if err != nil {
			log.Printf("Error getting file info %s: %v", filePath, err)
			continue
		}

		existingSheet, exists := pathsInDb[filePath]
		if exists {
			if existingSheet.FileHash != hash {
				// Case 1: File has been altered -> update hash
				existingSheet.FileHash = hash
				existingSheet.UpdatedAt = time.Now()
				if err := database.DB.Save(existingSheet).Error; err != nil {
					log.Printf("Error updating sheet hash for %s: %v", filePath, err)
				}
			}
		} else {
			sheetsWithHash, hasHash := hashToSheets[hash]
			if hasHash {
				for _, s := range sheetsWithHash {
					if _, err := os.Stat(s.FilePath); os.IsNotExist(err) {
						// Case 2: File has been renamed or moved -> update path
						s.FilePath = filePath
						s.UpdatedAt = time.Now()
						if err := database.DB.Save(s).Error; err != nil {
							log.Printf("Error updating sheet path for %s: %v", filePath, err)
						}
						break
					}
				}
			} else {
				// Case 3: New sheets file -> Add to database
				uuid, err := handlers.GenerateNonexistentSheetUuid()
				if err != nil {
					log.Printf("Error generating uuid: %v", err)
					continue
				}
				newSheet := models.Sheet{
					Uuid:      *uuid,
					Title:     file.Name(), // use filename as title
					FilePath:  filePath,
					FileSize:  info.Size(),
					FileHash:  hash,
					CreatedAt: time.Now(),
					UpdatedAt: time.Now(),
				}
				if err := database.DB.Create(&newSheet).Error; err != nil {
					log.Printf("Error creating new sheet for %s: %v", filePath, err)
				}
			}
		}
	}

	return nil
}
