package oauth

import (
	"github.com/veypi/vbase/internal/model"
	"github.com/veypi/vigo"
)

// UserInfoResponse 用户信息响应 (OIDC标准格式)
type UserInfoResponse struct {
	Sub               string   `json:"sub"`                 // 用户唯一标识
	Name              string   `json:"name,omitempty"`      // 全名
	Nickname          string   `json:"nickname,omitempty"`  // 昵称
	PreferredUsername string   `json:"preferred_username,omitempty"`
	Profile           string   `json:"profile,omitempty"`
	Picture           string   `json:"picture,omitempty"`   // 头像
	Website           string   `json:"website,omitempty"`
	Email             string   `json:"email,omitempty"`
	EmailVerified     bool     `json:"email_verified,omitempty"`
	Phone             string   `json:"phone,omitempty"`
	PhoneVerified     bool     `json:"phone_verified,omitempty"`
	Gender            string   `json:"gender,omitempty"`
	Birthdate         string   `json:"birthdate,omitempty"`
	Zoneinfo          string   `json:"zoneinfo,omitempty"`
	Locale            string   `json:"locale,omitempty"`
	UpdatedAt         int64    `json:"updated_at,omitempty"`
	Orgs              []OrgClaim `json:"orgs,omitempty"`    // 扩展字段：用户所属组织
}

// OrgClaim 组织声明
type OrgClaim struct {
	OrgID  string   `json:"org_id"`
	Name   string   `json:"name"`
	Code   string   `json:"code"`
	Roles  []string `json:"roles"`
	Status int      `json:"status"`
}

// UserInfo 用户信息端点 (OIDC)
// GET /oauth/userinfo
func UserInfo(x *vigo.X) (*UserInfoResponse, error) {
	// 从context获取当前用户
	userID, ok := x.Get("oauth_user_id").(string)
	if !ok || userID == "" {
		return nil, vigo.ErrNotAuthorized.WithString("invalid_token")
	}

	// 获取scope决定返回哪些字段
	scope, _ := x.Get("oauth_scope").(string)
	scopes := parseScopes(scope)

	var user model.User
	if err := model.DB.First(&user, "id = ?", userID).Error; err != nil {
		return nil, vigo.ErrNotFound.WithString("user not found")
	}

	resp := &UserInfoResponse{
		Sub: user.ID,
	}

	// 根据scope返回相应字段
	if contains(scopes, "profile") {
		resp.Name = user.Nickname
		resp.Nickname = user.Nickname
		resp.PreferredUsername = user.Username
		resp.Picture = user.Avatar
		resp.UpdatedAt = user.UpdatedAt.Unix()
	}

	if contains(scopes, "email") {
		resp.Email = user.Email
		resp.EmailVerified = user.EmailVerified
	}

	if contains(scopes, "phone") {
		resp.Phone = user.Phone
		resp.PhoneVerified = user.PhoneVerified
	}

	// 如果请求了org scope，返回组织信息
	if contains(scopes, "org") {
		resp.Orgs = getUserOrgClaims(userID)
	}

	return resp, nil
}

// DiscoveryResponse OIDC发现文档响应
type DiscoveryResponse struct {
	Issuer                            string   `json:"issuer"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint"`
	UserinfoEndpoint                  string   `json:"userinfo_endpoint"`
	RevocationEndpoint                string   `json:"revocation_endpoint"`
	IntrospectionEndpoint             string   `json:"introspection_endpoint"`
	JWKSUri                           string   `json:"jwks_uri"`
	ScopesSupported                   []string `json:"scopes_supported"`
	ResponseTypesSupported            []string `json:"response_types_supported"`
	GrantTypesSupported               []string `json:"grant_types_supported"`
	SubjectTypesSupported             []string `json:"subject_types_supported"`
	IDTokenSigningAlgValuesSupported  []string `json:"id_token_signing_alg_values_supported"`
	TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
	ClaimsSupported                   []string `json:"claims_supported"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported"`
}

// Discovery OIDC发现文档端点
// GET /.well-known/openid-configuration
func Discovery(x *vigo.X) (*DiscoveryResponse, error) {
	baseURL := "https://" + x.Request.Host // 生产环境应该使用配置

	return &DiscoveryResponse{
		Issuer:                baseURL,
		AuthorizationEndpoint: baseURL + "/oauth/authorize",
		TokenEndpoint:         baseURL + "/oauth/token",
		UserinfoEndpoint:      baseURL + "/oauth/userinfo",
		RevocationEndpoint:    baseURL + "/oauth/revoke",
		IntrospectionEndpoint: baseURL + "/oauth/introspect",
		JWKSUri:               baseURL + "/oauth/jwks",
		ScopesSupported: []string{
			"openid",
			"profile",
			"email",
			"phone",
			"org",
			"roles",
			"offline_access",
		},
		ResponseTypesSupported: []string{"code", "token", "id_token"},
		GrantTypesSupported: []string{
			"authorization_code",
			"refresh_token",
			"client_credentials",
		},
		SubjectTypesSupported:            []string{"public"},
		IDTokenSigningAlgValuesSupported: []string{"RS256"},
		TokenEndpointAuthMethodsSupported: []string{
			"client_secret_basic",
			"client_secret_post",
		},
		ClaimsSupported: []string{
			"sub",
			"name",
			"nickname",
			"preferred_username",
			"picture",
			"email",
			"email_verified",
			"phone",
			"phone_verified",
			"updated_at",
			"orgs",
		},
		CodeChallengeMethodsSupported: []string{"S256", "plain"},
	}, nil
}

// JWKSResponse JWKS响应
type JWKSResponse struct {
	Keys []JWK `json:"keys"`
}

// JWK JSON Web Key
type JWK struct {
	Kty string `json:"kty"`
	Kid string `json:"kid"`
	Use string `json:"use"`
	N   string `json:"n"`
	E   string `json:"e"`
	Alg string `json:"alg"`
}

// JWKS 公钥端点
// GET /oauth/jwks
func JWKS(x *vigo.X) (*JWKSResponse, error) {
	// 返回JWT签名公钥
	// 实际实现需要从配置的私钥中提取公钥信息
	// 这里简化返回
	return &JWKSResponse{
		Keys: []JWK{
			{
				Kty: "RSA",
				Kid: "default",
				Use: "sig",
				Alg: "RS256",
				// N和E应该从实际公钥计算得出
			},
		},
	}, nil
}

// helper functions
func getUserOrgClaims(userID string) []OrgClaim {
	var members []model.OrgMember
	if err := model.DB.Where("user_id = ? AND status = ?", userID, model.MemberStatusActive).Find(&members).Error; err != nil {
		return nil
	}

	if len(members) == 0 {
		return []OrgClaim{}
	}

	result := make([]OrgClaim, 0, len(members))
	for _, m := range members {
		var org model.Org
		if err := model.DB.First(&org, "id = ?", m.OrgID).Error; err != nil {
			continue
		}

		roles := []string{}
		if m.RoleIDs != "" {
			roles = parseScopes(m.RoleIDs) // 复用parseScopes来split
		}

		result = append(result, OrgClaim{
			OrgID:  m.OrgID,
			Name:   org.Name,
			Code:   org.Code,
			Roles:  roles,
			Status: m.Status,
		})
	}

	return result
}
