package logic

import (
	"fmt"
	"fusenapi/model/gmodel"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/wevent"
	"net/http"
	"time"

	"context"

	"fusenapi/server/auth/internal/svc"
	"fusenapi/server/auth/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpx"
	"gorm.io/gorm"
)

type UserEmailConfirmationLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserEmailConfirmationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserEmailConfirmationLogic {
	return &UserEmailConfirmationLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// 处理进入前逻辑w,r
// func (l *UserEmailConfirmationLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }

func FinishRegister(svcCtx *svc.ServiceContext, user *gmodel.FsUser, token *auth.RegisterToken) error {
	// 创建签证
	jwtToken, err := auth.GenerateJwtTokenUint64(
		auth.StringToHash(*user.PasswordHash),
		svcCtx.Config.Auth.AccessExpire,
		time.Now().UTC().Unix(),
		user.Id,
		0,
	)

	if err != nil {
		return err
	}

	event := wevent.NewWebsocketEventSuccess(wevent.UserEmailRegister, token.TraceId)
	event.Data = wevent.DataEmailRegister{
		JwtToken: jwtToken,
	}
	err = wevent.CommonNotify(svcCtx.Config.WebsocketAddr, token.Wid, event)
	if err != nil {
		// logx.Error(err, token.TraceId)
		return err
	}

	return nil
}

func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEmailConfirmation, userinfo *auth.UserInfo) (resp *basic.Response) {
	// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
	// userinfo 传入值时, 一定不为null

	switch auth.OperateType(req.OpType) {
	case auth.OpTypeRegister:

		token, err := l.svcCtx.OAuthTokenManger.Decrypt(req.Token)
		if err != nil {
			logx.Error(err)
			return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
		}

		if time.Since(token.CreateAt) > 30*time.Minute {
			return resp.SetStatusWithMessage(basic.CodeOAuthConfirmationTimeoutErr, "Verification links expire after 30 minute.")
		}

		// logx.Error(token.Platform)
		switch token.Platform {
		case string(auth.PLATFORM_GOOGLE):
			//   谷歌平台的注册流程
			user, err := l.svcCtx.AllModels.FsUser.RegisterByGoogleOAuth(l.ctx, token)
			if err != nil {
				logx.Error(err, token.TraceId)
				return resp.SetStatus(basic.CodeDbSqlErr, err)
			}

			err = FinishRegister(l.svcCtx, user, token)
			if err != nil {
				logx.Error(err)
			}
			logx.Info("success", token.TraceId)

		case string(auth.PLATFORM_FACEBOOK):

		case string(auth.PLATFORM_FUSEN):
			// log.Println("aaaa", token)
			user, err := l.svcCtx.AllModels.FsUser.RegisterByFusen(l.ctx, token)
			if err != nil && err != gorm.ErrRecordNotFound {
				logx.Error(err)
				return resp.SetStatusWithMessage(basic.CodeDbSqlErr, err.Error())
			}
			err = FinishRegister(l.svcCtx, user, token)
			if err != nil {
				logx.Error(err)
			}
			logx.Info("success:", token.TraceId)
		}
	case auth.OpTypeResetToken:

		rt, err := l.svcCtx.ResetTokenManger.Decrypt(req.Token) // ResetToken
		if err != nil {
			logx.Error(err)
			return resp.SetStatus(basic.CodeOAuthResetTokenDecryptErr, err)
		}

		if time.Since(rt.CreateAt) > 30*time.Minute {
			return resp.SetStatusWithMessage(basic.CodeOAuthConfirmationTimeoutErr, "Verification links expire after 30 minute.")
		}

		// TODO: 存储
		if rt.OperateType != auth.OpTypeResetToken {
			return resp.SetStatus(basic.CodeOAuthTypeErr, fmt.Errorf("error OperateType: rt.OperateType != auth.OpTypeResetToken"))
		}

		err = l.svcCtx.AllModels.FsUser.Transaction(l.ctx, func(tx *gorm.DB) error {
			user := &gmodel.FsUser{Id: int64(rt.UserId)}
			err := tx.Take(user).Error
			if err != nil {
				return err
			}
			if *user.PasswordHash != rt.OldPassword {
				return fmt.Errorf("password had been reset")
			}
			return tx.Update("PasswordHash", rt.NewPassword).Error
		})

		if err != nil {
			return resp.SetStatus(basic.CodeDbSqlErr, err)
		}

		event := wevent.NewWebsocketEventSuccess(wevent.UserResetToken, rt.TraceId)
		err = wevent.CommonNotify(l.svcCtx.Config.MainAddress, rt.Wid, event)
		if err != nil {
			logx.Error(err, rt.TraceId)
			return resp.SetStatus(basic.CodeResetPasswordErr, err)
		}

		return resp.SetStatus(basic.CodeOK)

	default:
		return resp.SetStatus(basic.CodeOAuthRegisterTokenErr)
	}

	return resp.SetStatus(basic.CodeOK)
}

// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
func (l *UserEmailConfirmationLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
	if resp.Code == 200 {
		successHtml := `<!DOCTYPE html>
		<html>
		<head>
		  <title>Registration Successful</title>
		  
		  <style>
		  body {
			font-family: sans-serif;
			font-size: 16px; 
		  }
		  
		  h1 {
			font-size: 24px;
			color: red;
		  }
		  
		  @media screen and (max-width: 480px) {
			body {
			  font-size: 14px;   
			}
			
			h1 {
			   font-size: 18px;
			}
		  }
		  </style>
		  
		</head>
		
		<body>
		
		  <h1>Congratulations! Your registration is successful.</h1>
		
		  <p>Thank you for registering on our website. Your account has been activated.</p>
		
		  <p>You can now login using your email address and password to enjoy full services and features on our website.</p>
		
		  <p>Thanks again for your trust and support. If you have any questions, please feel free to contact us.</p>
		
		  <p>We wish you a pleasant experience!</p>
		
		</body>
		</html>`
		w.Write([]byte(successHtml))
		httpx.Ok(w)
	} else {

		errorHtml := `
		<!DOCTYPE html>
		<html>
		<head>
		  <title>Failed to register</title>
		  <style>
			body {
			  font-family: sans-serif; 
			  font-size: 16px;
			}
			
			h1 {
			  font-size: 24px;
			  color: blue;  
			}
			
			@media screen and (max-width: 480px) {
			  body {
				font-size: 14px;  
			  }
			  
			  h1 {
				font-size: 18px;
			  }
			}
		  </style>
		</head>
		<body>
		  <h1>%s</h1>  
		</body>
		</html>
		`

		errorHtml = fmt.Sprintf(errorHtml, resp.Message)
		w.Write([]byte(errorHtml))
		httpx.Ok(w)
	}
}