package server

import (
	"container/list"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"path"
	"reflect"
	"strings"

	"git.pyer.club/kingecg/gohttpd/model"
	"git.pyer.club/kingecg/gologger"
	"github.com/golang-jwt/jwt/v5"
)

type Middleware func(w http.ResponseWriter, r *http.Request, next http.Handler)

type MiddlewareLink struct {
	*list.List
}

func IsEqualMiddleware(a, b Middleware) bool {
	if a == nil && b == nil {
		return true
	}
	if a == nil || b == nil {
		return false
	}
	return reflect.ValueOf(a).Pointer() == reflect.ValueOf(b).Pointer()
}
func (ml *MiddlewareLink) Add(m Middleware) {
	if m == nil {
		return
	}

	if ml.List.Len() == 0 {
		ml.PushBack(m)
	} else {
		if IsEqualMiddleware(m, Done) {
			return
		}
		el := ml.Back()
		ml.InsertBefore(m, el)
	}
}

//	func (ml *MiddlewareLink) ServeHTTP(w http.ResponseWriter, r *http.Request) bool {
//		canContinue := true
//		next := func() {
//			canContinue = true
//		}
//		for e := ml.Front(); e != nil && canContinue; e = e.Next() {
//			canContinue = false
//			e.Value.(Middleware)(w, r, next)
//			if !canContinue {
//				break
//			}
//		}
//		return canContinue
//	}

func (ml *MiddlewareLink) wrap(m Middleware, next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		m(w, r, next)
	})
}
func (ml *MiddlewareLink) WrapHandler(next http.Handler) http.Handler {
	if ml.Back() == nil {
		return next
	}

	var handler http.Handler = next

	for e := ml.Back(); e != nil; e = e.Prev() {

		middleware, ok := e.Value.(Middleware)
		if !ok {
			break
		}

		handler = ml.wrap(middleware, handler)
	}
	return handler
}
func NewMiddlewareLink() *MiddlewareLink {
	ml := &MiddlewareLink{list.New()}
	ml.Add(Done)
	return ml
}

func BasicAuth(w http.ResponseWriter, r *http.Request, next http.Handler) {
	config := model.GetConfig()

	if config.Admin.Username == "" || config.Admin.Password == "" {
		next.ServeHTTP(w, r)
		return
	}
	user, pass, ok := r.BasicAuth()
	if ok && user == config.Admin.Username && pass == config.Admin.Password {
		next.ServeHTTP(w, r)
	} else {
		w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
		http.Error(w, "Unauthorized.", http.StatusUnauthorized)
	}
}
func JwtAuth(w http.ResponseWriter, r *http.Request, next http.Handler) {
	l := gologger.GetLogger("JwtAuth")
	config := model.GetConfig()
	jwtConfig := config.Admin.Jwt
	if jwtConfig.Secret == "" || path.Base(r.URL.Path) == "login" {
		next.ServeHTTP(w, r)
		return
	}
	// 从cookie中获取token
	tokenCookie, err := r.Cookie("auth_token")
	if err != nil {
		http.Error(w, "Unauthorized.", http.StatusUnauthorized)
		return
	}
	tokenString := tokenCookie.Value
	token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 确保签名方法是正确的
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(jwtConfig.Secret), nil
	})
	if err != nil {
		l.Error("Failed to parse JWT: %v", err)
		http.Error(w, "Unauthorized.", http.StatusUnauthorized)
		return
	}
	if claims, ok := token.Claims.(*jwt.RegisteredClaims); ok && token.Valid {
		// 验证通过，将用户信息存储在请求上下文中
		ctx := context.WithValue(r.Context(), "user", claims)
		next.ServeHTTP(w, r.WithContext(ctx))
		return
	}
	http.Error(w, "Unauthorized.", http.StatusUnauthorized)
}

func RecordAccess(w http.ResponseWriter, r *http.Request, next http.Handler) {
	model.Incr(r.Host)
	next.ServeHTTP(w, r)
}
func Parse[T any](w http.ResponseWriter, r *http.Request, next http.Handler) {

	if r.Method == "POST" || r.Method == "PUT" {
		//判断r的content-type是否是application/x-www-form-urlencoded
		if r.Header.Get("Content-Type") == "application/x-www-form-urlencoded" {
			r.ParseForm()

		} else if r.Header.Get("Content-Type") == "multipart/form-data" {
			r.ParseMultipartForm(r.ContentLength)

		} else {
			// 判断r的content-type是否是application/json
			contentType := r.Header.Get("Content-Type")
			if strings.Contains(contentType, "application/json") {
				var t T
				// 读取json数据
				if err := json.NewDecoder(r.Body).Decode(&t); err != nil {
					http.Error(w, err.Error(), http.StatusBadRequest)
					return
				}
				ctx := r.Context()
				m := ctx.Value(RequestCtxKey("data")).(map[string]interface{})
				if m != nil {
					m["data"] = t
				}

			}
		}

	}
	next.ServeHTTP(w, r)
}

func Done(w http.ResponseWriter, r *http.Request, next http.Handler) {
	next.ServeHTTP(w, r)
}
