package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"syscall/js"

	"github.com/thegrumpylion/jsref"

	"covergen/pkg/covergen"
)

type jsmap = map[string]interface{}

type covergenArgs struct {
	Customer     string `jsref:"customer"`
	Number       string `jsref:"number"`
	NumberPrefix string `jsref:"numberPrefix"`
	HLColor      string `jsref:"hlColor"`
}

func parseHexColor(s string) (c covergen.Color, err error) {
	switch len(s) {
	case 7:
		_, err = fmt.Sscanf(s, "#%02x%02x%02x", &c.R, &c.G, &c.B)
	case 4:
		_, err = fmt.Sscanf(s, "#%1x%1x%1x", &c.R, &c.G, &c.B)
		// Double the hex digits:
		c.R *= 17
		c.G *= 17
		c.B *= 17
	default:
		err = fmt.Errorf("invalid length, must be 7 or 4")

	}
	return
}

func settingsFromValue(arg js.Value) (*covergen.CoverSettings, error) {
	settings := covergenArgs{
		NumberPrefix: "offerte",
	}
	err := jsref.Unmarshal(&settings, arg)
	if err != nil {
		return nil, err
	}

	if settings.Number == "" {
		return nil, errors.New("number: shouldn't be empty")
	}

	if settings.Customer == "" {
		return nil, errors.New("customer: shouldn't be empty")
	}

	color := covergen.Color{R: 255}
	if settings.HLColor != "" {
		color, err = parseHexColor(settings.HLColor)
		if err != nil {
			return nil, fmt.Errorf("hlColor: %w", err)
		}
	}

	return &covergen.CoverSettings{
		Number:       settings.Number,
		NumberPrefix: settings.NumberPrefix,
		CustomerName: settings.Customer,
		HLColor:      color,
	}, nil
}

func generateCover(this js.Value, args []js.Value) interface{} {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("recovered", r)
		}
	}()

	if len(args) != 1 {
		return jsmap{"error": "missing argument"}
	}

	arg := args[0]
	if arg.Type() != js.TypeObject {
		return jsmap{"error": "expected object"}
	}

	settings, err := settingsFromValue(arg)
	if err != nil {
		return jsmap{"error": err.Error()}
	}

	pdf, err := covergen.GenerateInvoice(*settings)
	if err != nil {
		return jsmap{"error": err.Error()}
	}

	var buf bytes.Buffer
	if err = pdf.Output(&buf); err != nil {
		return jsmap{"error": err.Error()}
	}

	s := buf.Bytes()
	sum := sha256.Sum256(s)
	fmt.Println("shasum", hex.EncodeToString(sum[:]))

	ta := js.Global().Get("Uint8Array").New(len(s))
	js.CopyBytesToJS(ta, s)
	return ta
}

func main() {
	js.Global().Set("covergen", js.FuncOf(generateCover))
	<-make(chan bool)
}
