package mfsr

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"fmt"
	"io"
	"os"
)

func unpackArchive(dist, binnom, path, out, atype string) error {
	switch atype {
	case "zip":
		return unpackZip(dist, binnom, path, out)
	case "tar.gz":
		return unpackTgz(dist, binnom, path, out)
	default:
		return fmt.Errorf("unrecognized archive type: %s", atype)
	}
}

func unpackTgz(dist, binnom, path, out string) error {
	fi, err := os.Open(path)
	if err != nil {
		return err
	}
	defer fi.Close()

	gzr, err := gzip.NewReader(fi)
	if err != nil {
		return err
	}

	defer gzr.Close()

	var bin io.Reader
	tarr := tar.NewReader(gzr)

loop:
	for {
		th, err := tarr.Next()
		switch err {
		default:
			return err
		case io.EOF:
			break loop
		case nil:
			// continue
		}

		if th.Name == dist+"/"+binnom {
			bin = tarr
			break
		}
	}

	if bin == nil {
		return fmt.Errorf("no binary found in downloaded archive")
	}

	return writeToPath(bin, out)
}

func writeToPath(rc io.Reader, out string) error {
	binfi, err := os.Create(out)
	if err != nil {
		return fmt.Errorf("error opening tmp bin path '%s': %s", out, err)
	}
	defer binfi.Close()

	_, err = io.Copy(binfi, rc)
	if err != nil {
		return err
	}

	return nil
}

func unpackZip(dist, binnom, path, out string) error {
	zipr, err := zip.OpenReader(path)
	if err != nil {
		return fmt.Errorf("error opening zipreader: %s", err)
	}

	defer zipr.Close()

	var bin io.ReadCloser
	for _, fis := range zipr.File {
		if fis.Name == dist+"/"+binnom {
			rc, err := fis.Open()
			if err != nil {
				return fmt.Errorf("error extracting binary from archive: %s", err)
			}

			bin = rc
		}
	}

	return writeToPath(bin, out)
}
