package lib

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"

	"gitlab.com/romalor/pdflib/pkg/components/attachment"
	"gitlab.com/romalor/pdflib/pkg/pdf"
)

func AppendToPdf(
	inputPdfFilePath string,
	inputXmlFilePath string,
	outputFilePath string,
	embedName string,
	description string,
) (err error) {
	logger := GetDebugLogger()
	logger.Log(fmt.Sprintf("enter appendToPdf(%s, %s, %s)", inputPdfFilePath, inputXmlFilePath, outputFilePath))
	defer func() {
		if err != nil {
			logger.Log("append err:", err)
		}
		logger.Log("leave appendToPdf")
	}()

	if inputPdfFilePath == "" {
		return errors.New("no input pdf file specified")
	}

	if inputXmlFilePath == "" {
		inputXmlFilePath = strings.TrimSuffix(inputPdfFilePath, filepath.Ext(inputPdfFilePath)) + ".xml"
	}

	if outputFilePath == "" {
		outputFilePath = strings.TrimSuffix(
			inputPdfFilePath,
			filepath.Ext(inputPdfFilePath),
		) + "_xml.pdf"
	}

	if description == "" {
		description = "Rechnung"
	}

	if embedName == "" {
		embedName = "factur-x.xml"
	}

	logger.Log(
		fmt.Sprintf(
			"pdfInput: '%s' xmlInput: '%s' output: '%s'",
			inputPdfFilePath,
			inputXmlFilePath,
			outputFilePath,
		),
	)

	var inputFile *os.File
	inputFile, err = os.Open(inputPdfFilePath)
	if err != nil {
		return err
	}
	defer inputFile.Close()

	var result io.Reader
	result, err = addAttachment(inputFile, inputXmlFilePath, embedName, description)
	if err != nil {
		return err
	}

	result, err = addXmpData(result)
	if err != nil {
		return err
	}

	var outputFile *os.File
	outputFile, err = os.Create(outputFilePath)
	if err != nil {
		return err
	}
	defer outputFile.Close()

	_, err = io.Copy(outputFile, result)
	if err != nil {
		return err
	}

	return nil
}

func addAttachment(
	data io.Reader,
	inputXmlFilePath string,
	embedName string,
	description string,
) (io.Reader, error) {
	doc, err := pdf.OpenReaderWithOptions(data, pdf.OpenOptions{
		Writable: true,
	})
	if err != nil {
		return nil, err
	}

	var inputXmlFile *os.File
	inputXmlFile, err = os.Open(inputXmlFilePath)
	if err != nil {
		return nil, err
	}

	var inputData []byte
	inputData, err = io.ReadAll(inputXmlFile)
	if err != nil {
		return nil, err
	}

	err = doc.AddAttachment(attachment.Attachment{
		Name:         embedName,
		Description:  description,
		MIMEType:     "text/xml",
		Size:         int64(len(inputData)),
		Relationship: "Alternative",
		ModDate:      time.Now(),
	}, inputData)
	if err != nil {
		return nil, err
	}

	result := bytes.NewBuffer([]byte{})
	_, err = doc.Writer().WriteTo(result)
	if err != nil {
		return nil, err
	}

	return result, nil
}

func addXmpData(data io.Reader) (io.Reader, error) {
	doc, err := pdf.OpenReaderWithOptions(data, pdf.OpenOptions{
		Writable: true,
	})
	if err != nil {
		return nil, err
	}

	var xmpData []byte
	xmpData, err = doc.XMPMetadata()
	if err != nil {
		return nil, err
	}

	xmpData, err = addFacturXXmpData(xmpData)
	if err != nil {
		return nil, err
	}

	err = doc.SetXMPMetadata(xmpData)
	if err != nil {
		return nil, err
	}

	xmpData, err = doc.XMPMetadata()
	if err != nil {
		return nil, err
	}

	result := bytes.NewBuffer([]byte{})
	_, err = doc.Writer().WriteTo(result)
	if err != nil {
		return nil, err
	}

	return result, nil
}
