package ytdlp

import (
	"context"
	"os"

	"git.kmsign.ru/royalcat/tstor/server/pkg/ctxbilly"
	"git.kmsign.ru/royalcat/tstor/server/pkg/kvsingle"
	"git.kmsign.ru/royalcat/tstor/server/pkg/rlog"
	"git.kmsign.ru/royalcat/tstor/server/pkg/ytdlp"
	"git.kmsign.ru/royalcat/tstor/server/src/tasks"
	"github.com/royalcat/ctxio"
	"github.com/royalcat/ctxprogress"
	"github.com/royalcat/kv"
)

type Controller struct {
	datafs     ctxbilly.Filesystem
	source     Source
	client     *ytdlp.Client
	cachedinfo *kvsingle.Value[string, ytdlp.Info]
}

func newYtdlpController(datafs ctxbilly.Filesystem, source Source, client *ytdlp.Client) *Controller {
	return &Controller{
		datafs: datafs,
		source: source,
		client: client,
	}
}

func (c *Controller) Source() Source {
	return c.source
}

const sizeApprox = 1024 * 1024 * 1024

func (c *Controller) Update(ctx context.Context, updater tasks.Updater) error {
	log := updater.Logger()
	ctxprogress.New(ctx)
	ctxprogress.Set(ctx, ctxprogress.RangeProgress{Current: 0, Total: 10})
	plst, err := c.client.Playlist(ctx, c.source.Url)
	ctxprogress.Set(ctx, ctxprogress.RangeProgress{Current: 1, Total: 10})
	ctxprogress.Range(ctx, plst, func(ctx context.Context, _ int, e ytdlp.Entry) bool {
		if e.OriginalURL == "" {
			log.Error("no URL in entry", rlog.Error(err))
			return true
		}

		info, err := c.Info(ctx)
		if err != nil {
			log.Error("error getting info", rlog.Error(err))
			return true
		}

		dwl := info.RequestedDownloads[0]

		fileinfo, err := c.datafs.Stat(ctx, dwl.Filename)
		if err != nil {
			log.Error("error getting file info", rlog.Error(err))
			return true
		}

		if fileinfo.Size()+sizeApprox > dwl.FilesizeApprox && fileinfo.Size()-sizeApprox < dwl.FilesizeApprox {
			log.Debug("file already downloaded", "filename", dwl.Filename)
			return true
		}

		file, err := c.datafs.OpenFile(ctx, dwl.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
		if err != nil {
			log.Error("error opening destination file", rlog.Error(err))
			return true
		}

		err = c.client.Download(ctx, info.OriginalURL, ctxio.IoWriter(ctx, file))
		if err != nil {
			return false
		}
		return true
	})
	ctxprogress.Set(ctx, ctxprogress.RangeProgress{Current: 2, Total: 2})
	if err != nil {
		return err
	}

	return nil
}

func (c *Controller) Info(ctx context.Context) (ytdlp.Info, error) {
	info, err := c.cachedinfo.Get(ctx)
	if err == nil {
		return info, nil
	}
	if err != kv.ErrKeyNotFound {
		return info, err
	}

	info, err = c.Info(ctx)
	if err != nil {
		return info, err
	}
	err = c.cachedinfo.Set(ctx, info)
	if err != nil {
		return info, err
	}
	return info, nil
}

func (c *Controller) Downloaded() error {
	return nil
}