// Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
// SPDX-License-Identifier: GPL-2.0-or-later

package client

import (
	"io"
	"net/http"
	"os"
	"time"

	"github.com/autobrr/autobrr/pkg/errors"

	"github.com/anacrolix/torrent/metainfo"
	"github.com/avast/retry-go"
	"github.com/rs/zerolog/log"
)

type DownloadFileResponse struct {
	Body     *io.ReadCloser
	FileName string
}

type DownloadTorrentFileResponse struct {
	MetaInfo    *metainfo.MetaInfo
	TmpFileName string
}

type HttpClient struct {
	http *http.Client
}

func NewHttpClient() *HttpClient {
	httpClient := &http.Client{
		Timeout: time.Second * 10,
	}
	return &HttpClient{
		http: httpClient,
	}
}

func (c *HttpClient) DownloadTorrentFile(url string, opts map[string]string) (*DownloadTorrentFileResponse, error) {
	if url == "" {
		return nil, errors.New("download_file: url can't be empty")
	}

	// Create tmp file
	tmpFile, err := os.CreateTemp("", "autobrr-")
	if err != nil {
		log.Error().Stack().Err(err).Msg("error creating temp file")
		return nil, err
	}
	defer tmpFile.Close()

	res := &DownloadTorrentFileResponse{}
	// try request and if fail run 3 retries
	err = retry.Do(func() error {
		resp, err := http.Get(url)
		if err != nil {
			return errors.New("error downloading file: %q", err)
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			return errors.New("error downloading file bad status: %d", resp.StatusCode)
		}

		nuke := func() {
			tmpFile.Seek(0, io.SeekStart)
			tmpFile.Truncate(0)
		}

		// Write the body to file
		_, err = io.Copy(tmpFile, resp.Body)
		if err != nil {
			nuke()
			return errors.New("error writing downloaded file: %v | %q", tmpFile.Name(), err)
		}

		meta, err := metainfo.Load(resp.Body)
		if err != nil {
			nuke()
			return errors.New("metainfo could not load file contents: %v | %q", tmpFile.Name(), err)
		}

		res = &DownloadTorrentFileResponse{
			MetaInfo:    meta,
			TmpFileName: tmpFile.Name(),
		}

		if res.TmpFileName == "" || res.MetaInfo == nil {
			nuke()
			return errors.New("tmp file error - empty body")
		}

		if len(res.MetaInfo.InfoBytes) < 1 {
			nuke()
			return errors.New("could not read infohash")
		}

		log.Debug().Msgf("successfully downloaded file: %v", tmpFile.Name())
		return nil
	},
		//retry.OnRetry(func(n uint, err error) { c.log.Printf("%q: attempt %d - %v\n", err, n, url) }),
		retry.Delay(time.Second*5),
		retry.Attempts(3),
		retry.MaxJitter(time.Second*1))

	if err != nil {
		res = nil
	}

	return res, err
}
