package lib

import (
	"archive/tar"
	"bufio"
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"net/url"
	"os"
	"path"

	"git.matterlinux.xyz/matter/tracker/log"
	"github.com/bigkevmcd/go-configparser"
)

type Package struct {
	Name    string   `json:"name"`
	Pool    *Pool    `json:"-"`
	Version string   `json:"version"`
	Depends []string `json:"depends"`
	Size    string   `json:"size"`
	Desc    string   `json:"desc"`
	Archive string   `json:"archive"`
}

func (p *Package) Files() []string {
	var (
		gzip_reader io.Reader
		header      *tar.Header
		result      []string
		file        *os.File
		err         error
	)

	if file, err = os.Open(p.Archive); err != nil {
		log.Error("Failed to open %s", p.Archive)
		return result
	}
	defer file.Close()

	if gzip_reader, err = gzip.NewReader(bufio.NewReader(file)); err != nil {
		log.Error("Failed to create reader for %s", p.Archive)
		return result
	}

	reader := tar.NewReader(gzip_reader)

	for header, err = reader.Next(); err == nil; header, err = reader.Next() {
		if header.Typeflag != tar.TypeReg {
			continue
		}

		if path.Base(header.Name) != "files.tar.gz" {
			continue
		}

		if result, err = GetFiles(reader); err == nil {
			break
		}

		log.Error("Failed to get file list for %s: %s", p.Archive, err.Error())
		return []string{}
	}

	return result
}

func (p *Package) URL() string {
	if nil == p.Pool {
		return ""
	}
	url, _ := url.JoinPath(p.Pool.Source, "src/branch/"+p.Pool.Branch+"/src", p.Name)
	return url
}

func (p *Package) DependsToStr() string {
	var depends string = ""
	for _, d := range p.Depends {
		depends += fmt.Sprintf("%s ", d)
	}
	return depends
}

func (p *Package) Load(r io.Reader) error {
	var (
		err     error
		size    int64
		section string = "DEFAULT"
		buffer  []byte
	)

	if buffer, err = io.ReadAll(r); err != nil {
		return err
	}

	if p.Depends, err = GetMultiple("depends", bytes.NewReader(buffer)); err != nil {
		return err
	}

	parser := configparser.New()
	if err = parser.ParseReader(bytes.NewReader(buffer)); err != nil {
		return err
	}

	for _, s := range parser.Sections() {
		if s == "DEFAULT" {
			continue
		}
		section = s
		break
	}

	if section == "DEFAULT" {
		return fmt.Errorf("DATA does not contain any sections")
	}

	p.Name = section

	if p.Version, err = parser.Get(section, "version"); err != nil {
		return err
	}

	if size, err = parser.GetInt64(section, "size"); err != nil {
		return err
	}
	p.Size = SizeFromBytes(size)

	if p.Desc, err = parser.Get(section, "desc"); err != nil {
		return err
	}

	return nil
}