package main

import (
	"encoding/base64"
	"net/http"
	"os"
	"path/filepath"
	"sync"

	"github.com/wailsapp/wails/v3/pkg/application"
)

const localMediaVideoPath = "/localmedia/video"

// VideoResult is returned when the user opens a video file.
type VideoResult struct {
	URL  string `json:"url"`
	Name string `json:"name"`
}

// FileService exposes native file dialogs and streams the current video.
type FileService struct {
	app *application.App

	mu         sync.RWMutex
	videoPath  string
	videoMod   os.FileInfo
}

func NewFileService(app *application.App) *FileService {
	return &FileService{app: app}
}

func (s *FileService) OpenVideo() (VideoResult, error) {
	path, err := s.app.Dialog.OpenFile().
		SetTitle("Open Video").
		CanChooseFiles(true).
		AddFilter("Video", "*.mp4;*.mov;*.webm;*.mkv").
		AddFilter("All Files", "*").
		PromptForSingleSelection()
	if err != nil {
		return VideoResult{}, err
	}
	if path == "" {
		return VideoResult{}, nil
	}

	info, err := os.Stat(path)
	if err != nil {
		return VideoResult{}, err
	}

	s.mu.Lock()
	s.videoPath = path
	s.videoMod = info
	s.mu.Unlock()

	return VideoResult{
		URL:  localMediaVideoPath,
		Name: filepath.Base(path),
	}, nil
}

func (s *FileService) OpenProject() (string, error) {
	path, err := s.app.Dialog.OpenFile().
		SetTitle("Open Project").
		CanChooseFiles(true).
		AddFilter("JSON", "*.json").
		AddFilter("All Files", "*").
		PromptForSingleSelection()
	if err != nil {
		return "", err
	}
	if path == "" {
		return "", nil
	}

	data, err := os.ReadFile(path)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

func (s *FileService) SaveProject(content string, defaultName string) error {
	if defaultName == "" {
		defaultName = "project.json"
	}

	path, err := s.app.Dialog.SaveFile().
		SetMessage("Save Project").
		SetFilename(defaultName).
		AddFilter("JSON", "*.json").
		AddFilter("All Files", "*").
		PromptForSingleSelection()
	if err != nil {
		return err
	}
	if path == "" {
		return nil
	}

	return os.WriteFile(path, []byte(content), 0o644)
}

func (s *FileService) SaveAudio(dataBase64 string, defaultName string) error {
	if defaultName == "" {
		defaultName = "keyboard_track.wav"
	}

	data, err := base64.StdEncoding.DecodeString(dataBase64)
	if err != nil {
		return err
	}

	path, err := s.app.Dialog.SaveFile().
		SetMessage("Export Audio").
		SetFilename(defaultName).
		AddFilter("WAV", "*.wav").
		AddFilter("All Files", "*").
		PromptForSingleSelection()
	if err != nil {
		return err
	}
	if path == "" {
		return nil
	}

	return os.WriteFile(path, data, 0o644)
}

func (s *FileService) serveVideo(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}

	s.mu.RLock()
	path := s.videoPath
	modTime := s.videoMod
	s.mu.RUnlock()

	if path == "" {
		http.NotFound(w, r)
		return
	}

	file, err := os.Open(path)
	if err != nil {
		http.Error(w, "video unavailable", http.StatusNotFound)
		return
	}
	defer file.Close()

	info, err := file.Stat()
	if err != nil {
		http.Error(w, "video unavailable", http.StatusNotFound)
		return
	}
	if modTime != nil && !info.ModTime().Equal(modTime.ModTime()) {
		s.mu.Lock()
		s.videoMod = info
		s.mu.Unlock()
	}

	http.ServeContent(w, r, info.Name(), info.ModTime(), file)
}
