/*
 * Flatten form data in PDF files, moving to content stream from annotations, so cannot be edited.
 * Note: Works for forms that have been filled in an editor and have the appearance streams generated.
 *
 * Run as: go run pdf_form_flatten.go <outputdir> <pdf files...>
 */

package main

import (
	"fmt"
	"os"
	"path/filepath"
	"sort"

	"github.com/unidoc/unipdf/v3/annotator"
	"github.com/unidoc/unipdf/v3/common/license"
	"github.com/unidoc/unipdf/v3/model"
)

func init() {
	// Make sure to load your metered License API key prior to using the library.
	// If you need a key, you can sign up and create a free one at https://cloud.unidoc.io
	err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
	if err != nil {
		panic(err)
	}
}

func main() {
	if len(os.Args) < 3 {
		fmt.Printf("Usage: go run pdf_form_flatten.go <outputdir> <input1.pdf> [input2.pdf] ...\n")
		os.Exit(1)
	}

	outputDir := os.Args[1]

	fails := map[string]string{}
	failKeys := []string{}
	processed := 0

	for i := 2; i < len(os.Args); i++ {
		inputPath := os.Args[i]
		name := filepath.Base(inputPath)
		outputPath := filepath.Join(outputDir, fmt.Sprintf("flattened_%s", name))
		err := flattenPdf(inputPath, outputPath)
		if err != nil {
			fmt.Printf("%s - Error: %v\n", inputPath, err)
			fails[inputPath] = err.Error()
			failKeys = append(failKeys, inputPath)
		}
		processed++
	}

	fmt.Printf("Total %d processed / %d failures\n", processed, len(failKeys))
	sort.Strings(failKeys)
	for _, k := range failKeys {
		fmt.Printf("%s: %v\n", k, fails[k])
	}
}

// flattenPdf flattens annotations and forms moving the appearance stream to the page contents so cannot be
// modified.
func flattenPdf(inputPath, outputPath string) error {
	f, err := os.Open(inputPath)
	if err != nil {
		return err
	}
	defer f.Close()

	pdfReader, err := model.NewPdfReader(f)
	if err != nil {
		return err
	}

	fieldAppearance := annotator.FieldAppearance{OnlyIfMissing: true}
	err = pdfReader.FlattenFields(true, fieldAppearance)
	if err != nil {
		return err
	}

	// AcroForm field is no longer needed.
	opt := &model.ReaderToWriterOpts{
		SkipAcroForm: true,
	}

	// Generate a PdfWriter instance from existing PdfReader.
	pdfWriter, err := pdfReader.ToWriter(opt)
	if err != nil {
		return err
	}

	// Write to file.
	err = pdfWriter.WriteToFile(outputPath)
	return err
}