package main

import (
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
)

// InboxWatcher watches the inbox directory for new files via inotify
type InboxWatcher struct {
	dir string
}

// StartInboxWatcher launches a background goroutine that watches the inbox directory
func StartInboxWatcher() {
	w := &InboxWatcher{dir: inboxDir}
	go w.run()
}

func (w *InboxWatcher) run() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Printf("❌ Inbox watcher failed to start: %v", err)
		return
	}
	defer watcher.Close()

	os.MkdirAll(w.dir, 0755)

	if err := watcher.Add(w.dir); err != nil {
		log.Printf("❌ Inbox watcher failed to watch %s: %v", w.dir, err)
		return
	}

	log.Printf("👁️  Inbox watcher started: %s", w.dir)

	// Debounce: wait for writes to finish before processing
	pending := make(map[string]time.Time)
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			// Track files on create or write (scanner may write in chunks)
			if event.Op&(fsnotify.Create|fsnotify.Write) != 0 {
				name := filepath.Base(event.Name)
				// Skip hidden files, temp files, and non-document files
				if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "._") {
					continue
				}
				ext := strings.ToLower(filepath.Ext(name))
				allowed := map[string]bool{
					".pdf": true, ".jpg": true, ".jpeg": true, ".png": true,
					".tiff": true, ".tif": true, ".bmp": true,
					".doc": true, ".docx": true, ".odt": true, ".rtf": true,
					".xls": true, ".xlsx": true, ".ppt": true, ".pptx": true,
					".txt": true, ".csv": true, ".md": true,
				}
				if !allowed[ext] {
					continue
				}
				pending[event.Name] = time.Now()
			}

		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			log.Printf("Inbox watcher error: %v", err)

		case <-ticker.C:
			// Process files that haven't been written to for 2 seconds (transfer complete)
			now := time.Now()
			for path, lastWrite := range pending {
				if now.Sub(lastWrite) < 2*time.Second {
					continue
				}
				delete(pending, path)

				// Verify file still exists and has content
				info, err := os.Stat(path)
				if err != nil || info.Size() == 0 {
					continue
				}

				w.processFile(path)
			}
		}
	}
}

func (w *InboxWatcher) processFile(filePath string) {
	fname := filepath.Base(filePath)
	log.Printf("📄 Inbox: new file %s", fname)

	// Check for duplicate
	hash, _ := FileHash(filePath)
	if existing, _ := GetDocument(hash); existing != nil && existing.Status == "ready" {
		log.Printf("  Already exists (%s), skipping", hash)
		os.Remove(filePath)
		return
	}

	// Create pending document (shows in UI immediately)
	InsertPendingDocument(hash, fname)

	// Process async (same pipeline as web upload)
	go func() {
		if doc, err := ProcessDocument(filePath); err != nil {
			log.Printf("Inbox process error for %s: %v", fname, err)
			UpdateDocumentStatus(hash, "error")
		} else {
			log.Printf("📥 Processed: %s → %s/%s", fname, doc.Category, doc.ID)
		}
	}()
}
