// Package filewite adds a function to write the data stream to a file
package filewrite

import (
	"context"
	"fmt"
	"os"
	"path"
	"time"

	"github.com/chathaway-codes/home-sensors/v2/internal/h264video"
	"github.com/chathaway-codes/home-sensors/v2/internal/watcher/config"
	"github.com/rs/zerolog/log"
)

var Default = &Mod{}

type FileWrite struct {
	cfg        *config.Config
	cancelFunc func()
	ctx        context.Context
	video      *h264video.Video
}

func New(video *h264video.Video, cfg *config.Config) (*FileWrite, error) {
	ctx, cancelFunc := context.WithCancel(context.Background())

	return &FileWrite{
		cfg:        cfg,
		cancelFunc: cancelFunc,
		video:      video,
		ctx:        ctx,
	}, nil

}

// Run launches the commands and begins creating data. It will block until Done is called.
func (v *FileWrite) Run() {
	// Confirm that the target directory is a directory
	stat, err := os.Stat(v.cfg.LocalCopy)
	log := log.With().Str("directory", v.cfg.LocalCopy).Logger()
	if err != nil {
		log.Fatal().Err(err).Msg("failed to open path")
	}
	if !stat.IsDir() {
		log.Fatal().Msg("path is not directory")
	}
	// Start snooping
	videoCh, codec, done := v.video.Join()
	defer done()

	// TODO: what do with codec?
	log.Info().Str("codec", codec).Msg("got video codec")

	now := time.Now()
	fileName := path.Join(v.cfg.LocalCopy, fmt.Sprintf("%s.h264", now.Format("2006-01-02T15:04:05")))
	writer, err := os.Create(fileName)
	if err != nil {
		log.Fatal().Err(err).Str("file", fileName).Msg("failed to create file")
	}

	for bytes := range videoCh {
		select {
		case <-v.ctx.Done():
			return
		default:
			// do nothing
		}

		_, err := writer.Write(bytes)
		if err != nil {
			log.Fatal().Str("file", fileName).Err(err).Msg("failed to write bytes")
		}
		// Split it every half hour or so
		if time.Since(now) > time.Minute*30 {
			now = time.Now()
			if err := writer.Close(); err != nil {
				log.Fatal().Err(err).Msg("failed to close file")
			}
			fileName := path.Join(v.cfg.LocalCopy, fmt.Sprintf("%s.h264", now.Format("2006-01-02T15:04:05")))
			writer, err = os.Create(fileName)
			if err != nil {
				log.Fatal().Err(err).Str("file", fileName).Msg("failed to create file")
			}
		}
	}
}

// Done stops the processing.
func (v *FileWrite) Done() {
	v.cancelFunc()
}

type Mod struct{}

func (m *Mod) Get(video *h264video.Video) (*FileWrite, error) {
	cfg, err := config.Default.Get()
	if err != nil {
		return nil, err
	}
	return New(video, cfg)
}
