package svc

import (
	"errors"
	"fmt"
	"fusenapi/server/websocket/internal/config"
	"fusenapi/shared"
	"net/http"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"

	"fusenapi/initalize"
	"fusenapi/model/gmodel"

	"github.com/golang-jwt/jwt"
	"gorm.io/gorm"
)

type ServiceContext struct {
	Config      config.Config
	SharedState *shared.SharedState

	MysqlConn    *gorm.DB
	AllModels    *gmodel.AllModelsGen
	RabbitMq     *initalize.RabbitMqHandle
	AwsSession   *session.Session
	Repositories *initalize.Repositories
}

func NewServiceContext(c config.Config) *ServiceContext {
	conn := initalize.InitMysql(c.SourceMysql)
	config := aws.Config{
		Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token),
	}
	return &ServiceContext{
		Config:     c,
		MysqlConn:  conn,
		AllModels:  gmodel.NewAllModels(conn),
		RabbitMq:   initalize.InitRabbitMq(c.SourceRabbitMq, nil),
		AwsSession: session.Must(session.NewSession(&config)),
		Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
			GormDB:         conn,
			BLMServiceUrls: c.BLMService.Urls,
			AwsSession:     session.Must(session.NewSession(&config)),
		}),
	}
}

func (svcCtx *ServiceContext) ParseJwtToken(r *http.Request) (jwt.MapClaims, error) {
	AuthKey := r.Header.Get("Authorization")
	if AuthKey == "" {
		return nil, nil
	}
	AuthKey = AuthKey[7:]

	if len(AuthKey) <= 50 {
		return nil, errors.New(fmt.Sprint("Error parsing token, len:", len(AuthKey)))
	}

	token, err := jwt.Parse(AuthKey, func(token *jwt.Token) (interface{}, error) {
		// 检查签名方法是否为 HS256
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		// 返回用于验证签名的密钥
		return []byte(svcCtx.Config.Auth.AccessSecret), nil
	})
	if err != nil {
		return nil, errors.New(fmt.Sprint("Error parsing token:", err))
	}

	// 验证成功返回
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New(fmt.Sprint("Invalid token", err))
}