/*
 * SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
 * SPDX-License-Identifier: AGPL-3.0-only
 */

package redsys

import (
	"context"
	"fmt"

	"github.com/jackc/pgtype"
	"golang.org/x/text/language"

	"dev.tandem.ws/tandem/camper/pkg/auth"
	"dev.tandem.ws/tandem/camper/pkg/database"
)

type TransactionType int

const (
	TransactionTypeCharge         TransactionType = 0
	TransactionTypeRefund         TransactionType = 3
	TransactionTypePreauth        TransactionType = 1
	TransactionTypePreauthConfirm TransactionType = 2
	TransactionTypePreauthVoid    TransactionType = 9
	TransactionTypeSplitAuth      TransactionType = 7
	TransactionTypeSplitConfirm   TransactionType = 8
)

type Request struct {
	TransactionType  TransactionType
	Amount           string
	OrderNumber      string
	Product          string
	CardHolder       string
	SuccessURL       string
	FailureURL       string
	NotificationURL  string
	ConsumerLanguage language.Tag
}

type SignedRequest struct {
	MerchantParameters string
	Signature          string
	SignatureVersion   string
}

func SignRequest(ctx context.Context, conn *database.Conn, company *auth.Company, req *Request) (*SignedRequest, error) {
	row := conn.QueryRow(ctx, "select redsys_sign_request($1, $2)", company.ID, req)
	signed := &SignedRequest{}
	if err := row.Scan(&signed); err != nil {
		return nil, err
	}
	return signed, nil
}

func (src Request) EncodeText(ci *pgtype.ConnInfo, dst []byte) ([]byte, error) {
	typeName := database.RedsysRequestTypeName
	dt, ok := ci.DataTypeForName(typeName)
	if !ok {
		return nil, fmt.Errorf("unable to find oid for type name %v", typeName)
	}
	values := []interface{}{
		src.TransactionType,
		src.Amount,
		src.OrderNumber,
		src.Product,
		src.CardHolder,
		src.SuccessURL,
		src.FailureURL,
		src.NotificationURL,
		src.ConsumerLanguage,
	}
	ct := pgtype.NewValue(dt.Value).(*pgtype.CompositeType)
	if err := ct.Set(values); err != nil {
		return nil, err
	}
	return ct.EncodeText(ci, dst)
}

func (dst *SignedRequest) DecodeText(ci *pgtype.ConnInfo, src []byte) error {
	typeName := database.RedsysSignedRequestTypeName
	dt, ok := ci.DataTypeForName(typeName)
	if !ok {
		return fmt.Errorf("unable to find oid for type name %v", typeName)
	}
	ct := pgtype.NewValue(dt.Value).(*pgtype.CompositeType)
	if err := ct.DecodeText(ci, src); err != nil {
		return err
	}
	return ct.AssignTo(dst)
}
