package payment

import (
	"context"
	"net/http"

	"dev.tandem.ws/tandem/camper/pkg/auth"
	"dev.tandem.ws/tandem/camper/pkg/database"
	"dev.tandem.ws/tandem/camper/pkg/form"
	httplib "dev.tandem.ws/tandem/camper/pkg/http"
	"dev.tandem.ws/tandem/camper/pkg/locale"
	"dev.tandem.ws/tandem/camper/pkg/template"
)

type settingsForm struct {
	MerchantCode   *form.Input
	TerminalNumber *form.Input
	Environment    *form.Select
	Integration    *form.Select
	EncryptKey     *form.Input
}

func newSettingsForm(l *locale.Locale) *settingsForm {
	return &settingsForm{

		MerchantCode: &form.Input{
			Name: "merchant_code",
		},
		TerminalNumber: &form.Input{
			Name: "terminal_number",
		},
		Environment: &form.Select{
			Name: "environment",
			Options: []*form.Option{
				{
					Value: "test",
					Label: l.Pgettext("Test", "redsys environment"),
				},
				{
					Value: "live",
					Label: l.Pgettext("Live", "redsys environment"),
				},
			},
		},
		Integration: &form.Select{
			Name: "integration",
			Options: []*form.Option{
				{
					Value: "insite",
					Label: l.Pgettext("InSite", "redsys integration"),
				},
				{
					Value: "redirect",
					Label: l.Pgettext("Redirect", "redsys integration"),
				},
			},
		},
		EncryptKey: &form.Input{
			Name: "encrypt_key",
		},
	}
}

func (f *settingsForm) FillFromDatabase(ctx context.Context, company *auth.Company, conn *database.Conn) error {
	return conn.QueryRow(ctx, `
		select merchant_code
             , terminal_number::text
             , array[environment::text]
             , array[integration::text]
        from redsys
    	where company_id = $1`, company.ID).Scan(
		&f.MerchantCode.Val,
		&f.TerminalNumber.Val,
		&f.Environment.Selected,
		&f.Integration.Selected,
	)
}

func (f *settingsForm) MustRender(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company) {
	template.MustRenderAdmin(w, r, user, company, "payment/settings.gohtml", f)
}

func (f *settingsForm) Parse(r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}
	f.MerchantCode.FillValue(r)
	f.TerminalNumber.FillValue(r)
	f.Environment.FillValue(r)
	f.Integration.FillValue(r)
	f.EncryptKey.FillValue(r)
	return nil
}

func (f *settingsForm) Valid(l *locale.Locale) bool {
	v := form.NewValidator(l)

	if v.CheckRequired(f.MerchantCode, l.GettextNoop("Merchant code can not be empty.")) {
		if v.CheckExactLength(f.MerchantCode, 9, l.GettextNoop("Merchant code must be exactly nine digits long.")) {
			v.CheckValidInteger(f.MerchantCode, l.GettextNoop("Merchant code must be a number."))
		}
	}

	if v.CheckRequired(f.TerminalNumber, l.GettextNoop("Terminal number can not be empty.")) {
		message := l.GettextNoop("Terminal number must be a number between 1 and 999.")
		if v.CheckValidInteger(f.TerminalNumber, message) {
			if v.CheckMinInteger(f.TerminalNumber, 1, message) {
				v.CheckMaxInteger(f.TerminalNumber, 999, message)
			}
		}
	}

	v.CheckSelectedOptions(f.Environment, l.GettextNoop("Selected environment is not valid."))
	v.CheckSelectedOptions(f.Integration, l.GettextNoop("Selected integration is not valid."))

	if f.EncryptKey.Val != "" {
		v.CheckValidBase64(f.EncryptKey, l.GettextNoop("The merchant key is not valid."))
	}

	return v.AllOK
}

func updatePaymentSettings(w http.ResponseWriter, r *http.Request, user *auth.User, company *auth.Company, conn *database.Conn) {
	f := newSettingsForm(user.Locale)
	if ok, err := form.Handle(f, w, r, user); err != nil {
		return
	} else if !ok {
		f.MustRender(w, r, user, company)
		return
	}
	if err := conn.SetupRedsys(r.Context(), company.ID, f.MerchantCode.Val, f.TerminalNumber.Int(), f.Environment.Selected[0], f.Integration.Selected[0], f.EncryptKey.Val); err != nil {
		panic(err)
	}
	httplib.Redirect(w, r, "/admin/payments", http.StatusSeeOther)
}
