// meta4ra -- Metalink 4.0 utilities
// Copyright (C) 2021-2026 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"encoding/xml"
	"flag"
	"fmt"
	"io"
	"io/fs"
	"log"
	"os"
	"path"
	"time"

	meta4ra "go.stargrave.org/meta4ra/v2/internal"
)

func runCreate() {
	fn := flag.String("fn", "", "Filename")
	id := flag.String("id", "", "Optional file's identity")
	add := flag.String("add", "", "Add file to specified .meta4")
	mtime := flag.String("mtime", "", "Take that file's mtime as a Published date")
	desc := flag.String("desc", "", "Description")
	sigPGP := flag.String("sig-pgp", "",
		"Path to LibrePGP .asc signature file for inclusion")
	sigSSH := flag.String("sig-ssh", "",
		"Path to OpenSSH .sig signature file for inclusion")
	hashers := flag.String("hashers", meta4ra.HashersDefault,
		"hash-name commandline[\\n...]")
	noPublished := flag.Bool("no-published", false,
		"Do not include Published field")
	noGenerator := flag.Bool("no-generator", false,
		"Do not include Generator field")
	torrent := flag.String("torrent", "", "Torrent URL")
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(),
			"Usage: %s [options] [URL ...] <data >data.meta4\n", os.Args[0])
		flag.PrintDefaults()
		fmt.Fprint(flag.CommandLine.Output(), `
If URL is specified in "p|cc|URL" format, then "p" (may be empty)
will be the priority and "cc" (may be empty) is location.
`)
	}
	flag.Parse()

	if *showVersion {
		fmt.Println(meta4ra.Version())
		return
	}
	if *showWarranty {
		fmt.Println(meta4ra.Warranty)
		return
	}

	if *fn == "" {
		log.Fatal("empty -fn")
	}
	urls := make([]meta4ra.URL, 0, len(flag.Args()))
	for _, u := range flag.Args() {
		url, err := meta4ra.ParseURL(u)
		if err != nil {
			log.Fatal(err)
		}
		urls = append(urls, *url)
	}
	h, err := meta4ra.NewHasher(*hashers)
	if err != nil {
		log.Fatal(err)
	}
	h.Start()
	br := bufio.NewReaderSize(os.Stdin, meta4ra.BufLen)
	buf := make([]byte, meta4ra.BufLen)
	size, err := io.CopyBuffer(h, br, buf)
	if err != nil {
		log.Fatal(err)
	}
	dgsts, err := h.Sums()
	if err != nil {
		log.Fatal(err)
	}
	f := meta4ra.File{
		Name:        path.Base(*fn),
		Identity:    *id,
		Description: *desc,
		Size:        uint64(size),
		URLs:        urls,
		Hashes:      dgsts,
	}
	if *sigPGP != "" {
		var sigData []byte
		sigData, err = os.ReadFile(*sigPGP)
		if err != nil {
			log.Fatal(err)
		}
		f.Signature = append(f.Signature, meta4ra.Signature{
			MediaType: meta4ra.SigMediaTypePGP,
			Signature: "\n" + string(sigData),
		})
	}
	if *sigSSH != "" {
		var sigData []byte
		sigData, err = os.ReadFile(*sigSSH)
		if err != nil {
			log.Fatal(err)
		}
		f.Signature = append(f.Signature, meta4ra.Signature{
			MediaType: meta4ra.SigMediaTypeSSH,
			Signature: "\n" + string(sigData),
		})
	}
	if *torrent != "" {
		f.MetaURLs = []meta4ra.MetaURL{{MediaType: "torrent", URL: *torrent}}
	}

	var meta meta4ra.Metalink
	if *add == "" {
		var published time.Time
		if *mtime == "" {
			published = time.Now()
		} else {
			var fi fs.FileInfo
			fi, err = os.Stat(*mtime)
			if err != nil {
				log.Fatal(err)
			}
			published = fi.ModTime()
		}
		meta.Files = []meta4ra.File{f}
		if !*noPublished {
			t := published.UTC().Truncate(time.Second)
			meta.Published = &t
		}
		if !*noGenerator {
			meta.Generator = meta4ra.Generator
		}
	} else {
		var data []byte
		data, err = os.ReadFile(*add)
		if err != nil {
			log.Fatal(err)
		}
		err = xml.Unmarshal(data, &meta)
		if err != nil {
			log.Fatal(err)
		}
		meta.Files = append(meta.Files, f)
	}

	out, err := xml.MarshalIndent(&meta, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	os.Stdout.Write([]byte(xml.Header))
	os.Stdout.Write(out)
	os.Stdout.Write([]byte("\n"))
}
