package serve

import (
	"context"
	"fmt"
	"github.com/google/uuid"
	"github.com/loveuer/nf"
	"github.com/loveuer/nf/nft/log"
	"net/http"
	"time"
	"uauth/internal/middleware/auth"
	"uauth/internal/opt"
	"uauth/internal/serve/handler"
	"uauth/internal/store/cache"
	"uauth/internal/tool"
	"uauth/model"
)

func authenticateUser(username, password string) (bool, error) {
	// 这里你应该实现真实的用户认证逻辑
	// 为了简化,我们这里直接硬编码一个用户名和密码
	if username == "user" && password == "pass" {
		return true, nil
	}

	return false, fmt.Errorf("invalid username or password")
}

// 处理登录请求
func handleLogin(c *nf.Ctx) error {
	username := c.FormValue("username")
	password := c.FormValue("password")

	// 认证用户
	ok, err := authenticateUser(username, password)
	if err != nil || !ok {
		return c.Status(http.StatusUnauthorized).SendString("Unauthorized")
	}

	// 用户认证成功,重定向到授权页面
	http.Redirect(c.Writer, c.Request, "/authorize?client_id=12345&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fcallback&scope=read%20write", http.StatusFound)

	return nil
}

// 令牌请求的处理
func handleToken(c *nf.Ctx) error {
	var (
		err         error
		grantType   string
		code        string
		redirectURI string

		// 记录 user
		accessToken  string
		refreshToken string
		user         = new(model.User)
	)

	// 获取请求参数
	grantType = c.FormValue("grant_type")
	code = cache.Prefix + c.FormValue("code")
	redirectURI = c.FormValue("redirect_uri")

	// 简单验证
	if grantType != "authorization_code" {
		return c.Status(http.StatusBadRequest).SendString("Unsupported grant type")
	}

	if err = cache.Client.GetScan(tool.Timeout(3), code).Scan(&user); err != nil {
		return c.Status(http.StatusBadRequest).SendString("Invalid authorization code")
	}
	defer func() {
		// 清除已使用的授权码
		cache.Client.Del(tool.Timeout(3), code)
		_ = redirectURI
	}()

	// 生成访问令牌
	if accessToken, refreshToken, err = generateAccessToken(user); err != nil {
		return c.Status(http.StatusInternalServerError).SendString(err.Error())
	}

	c.Writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")

	// 返回访问令牌
	return c.JSON(map[string]string{
		"access_token":  accessToken,
		"refresh_token": refreshToken,
		"token_type":    "bearer",
		"expires_in":    "3600", // 访问令牌有效期(秒)
	})
}

func generateAccessToken(user *model.User) (accessToken string, refreshToken string, err error) {
	if accessToken, err = user.JwtEncode(); err != nil {
		return
	}

	refreshToken = uuid.New().String()[:8]

	if err = cache.Client.SetEx(tool.Timeout(3), cache.Prefix+"refresh_token", refreshToken, 24*time.Hour); err != nil {
		return
	}

	if err = cache.Client.SetEx(tool.Timeout(3), cache.Prefix+"access_token", accessToken, time.Hour); err != nil {
		return
	}

	return
}

func Run(ctx context.Context) error {

	app := nf.New()

	api := app.Group(opt.Cfg.Svc.Prefix)

	api.Get("/registry/user", handler.UserRegistryPage)
	api.Post("/registry/user", handler.UserRegistryAction)
	api.Post("/registry/client", handler.ClientRegistry)
	api.Get("/login", handler.LoginPage)
	api.Post("/login", handler.LoginAction)
	api.Get("/authorize", handler.Authorize)
	api.Post("/approve", handler.Approve)
	api.Post("/token", handleToken)

	api.Get("/after", auth.New(), func(c *nf.Ctx) error {
		return c.SendString("hello world")
	})

	log.Info("Starting server on: %s", opt.Cfg.Svc.Address)
	go func() {
		<-ctx.Done()
		_ = app.Shutdown(tool.Timeout(2))
	}()

	return app.Run(opt.Cfg.Svc.Address)
}