package pkg

import (
	"context"
	"fmt"
	"github.com/jackc/pgtype"
	"github.com/jackc/pgx/v4"
)

type NewInvoiceProductArray []*invoiceProductForm

func (src NewInvoiceProductArray) EncodeBinary(ci *pgtype.ConnInfo, buf []byte) ([]byte, error) {
	typeName := "new_invoice_product[]"
	dt, ok := ci.DataTypeForName(typeName)
	if !ok {
		return nil, fmt.Errorf("unable to find oid for type name %v", typeName)
	}
	var values [][]interface{}
	for _, form := range src {
		values = append(values, []interface{}{
			form.ProductId.Val,
			form.Name.Val,
			form.Description.Val,
			form.Price.Val,
			form.Quantity.Val,
			form.Discount.Float64() / 100.0,
			form.Tax.Selected,
		})
	}
	array := pgtype.NewValue(dt.Value).(pgtype.ValueTranscoder)
	if err := array.Set(values); err != nil {
		return nil, err
	}
	return array.EncodeBinary(ci, buf)
}

func registerPgTypes(ctx context.Context, conn *pgx.Conn) error {
	discountRateOID, err := registerPgType(ctx, conn, &pgtype.Numeric{}, "discount_rate")
	if err != nil {
		return err
	}
	newInvoiceProduct, err := pgtype.NewCompositeType(
		"new_invoice_product",
		[]pgtype.CompositeTypeField{
			{"product_id", pgtype.Int4OID},
			{"name", pgtype.TextOID},
			{"description", pgtype.TextOID},
			{"price", pgtype.TextOID},
			{"quantity", pgtype.Int4OID},
			{"discount_rate", discountRateOID},
			{"tax", pgtype.Int4ArrayOID},
		},
		conn.ConnInfo(),
	)
	if err != nil {
		return err
	}
	newInvoiceProductOID, err := registerPgType(ctx, conn, newInvoiceProduct, newInvoiceProduct.TypeName())
	if err != nil {
		return err
	}
	newInvoiceProductArray := pgtype.NewArrayType("new_invoice_product[]", newInvoiceProductOID, func() pgtype.ValueTranscoder {
		value := newInvoiceProduct.NewTypeValue()
		return value.(pgtype.ValueTranscoder)
	})
	_, err = registerPgType(ctx, conn, newInvoiceProductArray, newInvoiceProductArray.TypeName())
	if err != nil {
		return err
	}
	return nil
}

func registerPgType(ctx context.Context, conn *pgx.Conn, value pgtype.Value, name string) (oid uint32, err error) {
	if err = conn.QueryRow(ctx, "select $1::regtype::oid", name).Scan(&oid); err != nil {
		return
	}
	conn.ConnInfo().RegisterDataType(pgtype.DataType{Value: value, Name: name, OID: oid})
	return
}
