package watcher

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

	"docproc/processor"

	"github.com/fsnotify/fsnotify"
)

type Watcher struct {
	proc    *processor.Processor
	watcher *fsnotify.Watcher
	inbox   string
	stop    chan struct{}
}

func New(proc *processor.Processor) (*Watcher, error) {
	homeDir, _ := os.UserHomeDir()
	inbox := filepath.Join(homeDir, "documents", "inbox")

	// Ensure inbox exists
	os.MkdirAll(inbox, 0755)

	fsWatcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	if err := fsWatcher.Add(inbox); err != nil {
		fsWatcher.Close()
		return nil, err
	}

	return &Watcher{
		proc:    proc,
		watcher: fsWatcher,
		inbox:   inbox,
		stop:    make(chan struct{}),
	}, nil
}

func (w *Watcher) Watch() {
	// Process any existing files first
	w.processExisting()

	for {
		select {
		case event, ok := <-w.watcher.Events:
			if !ok {
				return
			}
			if event.Op&fsnotify.Create == fsnotify.Create {
				// Small delay to ensure file is fully written
				time.Sleep(500 * time.Millisecond)
				w.processFile(event.Name)
			}
		case err, ok := <-w.watcher.Errors:
			if !ok {
				return
			}
			log.Printf("Watcher error: %v", err)
		case <-w.stop:
			return
		}
	}
}

func (w *Watcher) processExisting() {
	entries, err := os.ReadDir(w.inbox)
	if err != nil {
		log.Printf("Failed to read inbox: %v", err)
		return
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}
		path := filepath.Join(w.inbox, entry.Name())
		w.processFile(path)
	}
}

func (w *Watcher) processFile(path string) {
	ext := strings.ToLower(filepath.Ext(path))
	if ext != ".pdf" && ext != ".png" && ext != ".jpg" && ext != ".jpeg" {
		return
	}

	if err := w.proc.ProcessFile(path); err != nil {
		log.Printf("Failed to process %s: %v", path, err)
	}
}

func (w *Watcher) Stop() {
	close(w.stop)
	w.watcher.Close()
}
