package controllers

import (
	"context"
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"log"

	"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/email"
	"git.badhouseplants.net/softplayer/softplayer-backend/internal/helpers/kube"
	ctrl "sigs.k8s.io/controller-runtime"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
)

type EmailSvc struct {
	Controller  ctrl.Manager
	Data        EmailData
	EmailConfig email.EmailConf
	DevMode     bool
}

type EmailData struct {
	UserID string
	Code   string
}

func (svc *EmailSvc) SendVerification(ctx context.Context) error {
	client := svc.Controller.GetClient()
	userns := &corev1.Namespace{}
	if err := client.Get(ctx, types.NamespacedName{
		Name: svc.Data.UserID,
	}, userns); err != nil {
		return err
	}

	userName, ok := userns.Labels["username"]
	if !ok {
		return errors.New("user not found")
	}
	accountData := &corev1.Secret{}
	if err := client.Get(ctx, types.NamespacedName{
		Namespace: "softplayer-accounts",
		Name:      userName,
	}, accountData); err != nil {
		return err
	}
	number := encodeToString(6)
	svc.Data.Code = number
	if !svc.DevMode {
		emailContent := "Subject: Softplayer verification code\r\n" + "\r\n" + fmt.Sprintf("Your verification code is %s", number)
		email := string(accountData.Data["email"])
		if err := svc.EmailConfig.SendEmail(email, emailContent); err != nil {
			return err
		}
	}
	emailCode := corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "email-verification-code",
			Namespace: svc.Data.UserID,
		},
		Data: map[string]string{
			"code": number,
		},
	}

	if err := kube.Create(ctx, client, &emailCode, true); err != nil {
		return err
	}
	return nil
}

func (svc *EmailSvc) ConfirmVerification(ctx context.Context) error {
	client := svc.Controller.GetClient()
	emailCode := &corev1.ConfigMap{}
	if err := client.Get(ctx, types.NamespacedName{
		Namespace: svc.Data.UserID,
		Name:      "email-verification-code",
	}, emailCode); err != nil {
		return err
	}

	if svc.Data.Code != emailCode.Data["code"] {
		log.Println(svc.Data.Code)
		log.Println(emailCode.Data["code"])
		return errors.New("wrong verification code")
	}
	if err := client.Delete(ctx, emailCode); err != nil {
		return err
	}

	userns := &corev1.Namespace{}
	if err := client.Get(ctx, types.NamespacedName{
		Name: svc.Data.UserID,
	}, userns); err != nil {
		return err
	}

	userns.Labels["email-verified"] = "true"
	if err := client.Update(ctx, userns); err != nil {
		return err
	}
	return nil
}

func encodeToString(max int) string {
	b := make([]byte, max)
	n, err := io.ReadAtLeast(rand.Reader, b, max)
	if n != max {
		panic(err)
	}
	for i := 0; i < len(b); i++ {
		b[i] = table[int(b[i])%len(table)]
	}
	return string(b)
}

var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}