package ytdl

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"strings"

	"go.fifitido.net/ytdl-web/pkg/utils"
	"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
	"golang.org/x/exp/slog"
)

type Options struct {
	args   []string
	stdin  io.Reader
	stdout io.Writer
	stderr io.Writer
	output interface{}
}

type Option func(*Options) error

func WithFormat(format string) Option {
	return func(opts *Options) error {
		opts.args = append(opts.args, "--format", format)
		return nil
	}
}

func WithCookieFile(cookieFile string) Option {
	return func(opts *Options) error {
		opts.args = append(opts.args, "--cookies", cookieFile)
		return nil
	}
}

func WithDumpJson(meta *metadata.Metadata) Option {
	return func(opts *Options) error {
		opts.args = append(opts.args, "--dump-single-json")
		opts.stdout = new(bytes.Buffer)
		opts.output = meta
		return nil
	}
}

func WithLoadJson(metadata *metadata.Metadata) Option {
	return func(opts *Options) error {
		opts.args = append(opts.args, "--load-info-json", "-")

		json, err := json.Marshal(metadata)
		if err != nil {
			return err
		}

		opts.stdin = bytes.NewBuffer(json)
		return nil
	}
}

func WithBrowserCookies(browser, keyring, profile, container string) Option {
	return func(opts *Options) error {
		var sb strings.Builder
		sb.WriteString(browser)

		if keyring != "" {
			sb.WriteByte('+')
			sb.WriteString(keyring)
		}

		if profile != "" {
			sb.WriteByte(':')
			sb.WriteString(profile)
		}

		if container != "" {
			sb.WriteByte(':')
			sb.WriteByte(':')
			sb.WriteString(container)
		}

		opts.args = append(opts.args, "--cookies-from-browser", sb.String())
		return nil
	}
}

func WithStreamOutput(output io.Writer) Option {
	return func(opts *Options) error {
		opts.args = append(opts.args, "--output", "-")
		opts.stdout = output
		return nil
	}
}

func WithDebug() Option {
	return func(opts *Options) error {
		opts.stdout = utils.LoggerWriter(slog.With("module", "ytdl"), slog.LevelDebug)
		opts.stderr = utils.LoggerWriter(slog.With("module", "ytdl"), slog.LevelDebug)
		return nil
	}
}

func WithPlaylistIndex(index int) Option {
	return func(opts *Options) error {
		opts.args = append(opts.args, "--playlist-items", fmt.Sprint(index+1))
		return nil
	}
}
