package oauth

import (
	"crypto/rand"
	"encoding/hex"
	"strings"

	"github.com/veypi/vbase/internal/api/middleware"
	"github.com/veypi/vbase/internal/model"
	"github.com/veypi/vigo"
)

// ClientRequest 客户端请求
type ClientRequest struct {
	Name          string   `json:"name" src:"json" desc:"应用名称"`
	Description   string   `json:"description" src:"json" desc:"应用描述"`
	RedirectURIs  []string `json:"redirect_uris" src:"json" desc:"回调地址列表"`
	GrantTypes    []string `json:"grant_types" src:"json" desc:"授权类型"`
	ResponseTypes []string `json:"response_types" src:"json" desc:"响应类型"`
	AllowedScopes []string `json:"allowed_scopes" src:"json" desc:"允许的权限范围"`
	TokenExpiry   int      `json:"token_expiry" src:"json" desc:"Token有效期(秒)"`
	RefreshExpiry int      `json:"refresh_expiry" src:"json" desc:"RefreshToken有效期(秒)"`
	OrgID         string   `json:"org_id" src:"json" desc:"所属组织ID(可选)"`
}

// ClientResponse 客户端响应
type ClientResponse struct {
	ID            string   `json:"id"`
	Name          string   `json:"name"`
	Description   string   `json:"description"`
	ClientID      string   `json:"client_id"`
	ClientSecret  string   `json:"client_secret,omitempty"`
	RedirectURIs  []string `json:"redirect_uris"`
	GrantTypes    []string `json:"grant_types"`
	ResponseTypes []string `json:"response_types"`
	AllowedScopes []string `json:"allowed_scopes"`
	TokenExpiry   int      `json:"token_expiry"`
	RefreshExpiry int      `json:"refresh_expiry"`
	OwnerID       string   `json:"owner_id"`
	OrgID         string   `json:"org_id,omitempty"`
	Status        int      `json:"status"`
	CreatedAt     string   `json:"created_at"`
}

// generateClientID 生成客户端ID
func generateClientID() string {
	b := make([]byte, 16)
	rand.Read(b)
	return hex.EncodeToString(b)
}

// generateClientSecret 生成客户端密钥
func generateClientSecret() string {
	b := make([]byte, 32)
	rand.Read(b)
	return hex.EncodeToString(b)
}

// CreateClient 创建OAuth客户端
func CreateClient(x *vigo.X, req *ClientRequest) (*ClientResponse, error) {
	userID := middleware.CurrentUser(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	// 默认值
	grantTypes := req.GrantTypes
	if len(grantTypes) == 0 {
		grantTypes = []string{model.GrantTypeAuthorizationCode, model.GrantTypeRefreshToken}
	}
	responseTypes := req.ResponseTypes
	if len(responseTypes) == 0 {
		responseTypes = []string{model.ResponseTypeCode}
	}
	allowedScopes := req.AllowedScopes
	if len(allowedScopes) == 0 {
		allowedScopes = []string{model.ScopeOpenID, model.ScopeProfile, model.ScopeEmail}
	}
	tokenExpiry := req.TokenExpiry
	if tokenExpiry == 0 {
		tokenExpiry = 3600
	}
	refreshExpiry := req.RefreshExpiry
	if refreshExpiry == 0 {
		refreshExpiry = 2592000 // 30天
	}

	client := &model.OAuthClient{
		Name:          req.Name,
		Description:   req.Description,
		ClientID:      generateClientID(),
		ClientSecret:  generateClientSecret(),
		RedirectURIs:  strings.Join(req.RedirectURIs, ","),
		GrantTypes:    strings.Join(grantTypes, ","),
		ResponseTypes: strings.Join(responseTypes, ","),
		AllowedScopes: strings.Join(allowedScopes, ","),
		TokenExpiry:   tokenExpiry,
		RefreshExpiry: refreshExpiry,
		OwnerID:       userID,
		Status:        1,
	}

	if req.OrgID != "" {
		// 检查用户是否是组织成员
		var member model.OrgMember
		if err := model.DB.Where("org_id = ? AND user_id = ? AND status = ?", req.OrgID, userID, model.MemberStatusActive).First(&member).Error; err != nil {
			return nil, vigo.ErrForbidden.WithString("you are not a member of this organization")
		}
		client.OrgID = req.OrgID
	}

	if err := model.DB.Create(client).Error; err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	return &ClientResponse{
		ID:            client.ID,
		Name:          client.Name,
		Description:   client.Description,
		ClientID:      client.ClientID,
		ClientSecret:  client.ClientSecret,
		RedirectURIs:  req.RedirectURIs,
		GrantTypes:    grantTypes,
		ResponseTypes: responseTypes,
		AllowedScopes: allowedScopes,
		TokenExpiry:   client.TokenExpiry,
		RefreshExpiry: client.RefreshExpiry,
		OwnerID:       client.OwnerID,
		OrgID:         client.OrgID,
		Status:        client.Status,
		CreatedAt:     client.CreatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}

// ListClientsRequest 客户端列表请求
type ListClientsRequest struct {
	Page     int    `json:"page" src:"query" default:"1" desc:"页码"`
	PageSize int    `json:"page_size" src:"query" default:"10" desc:"每页数量"`
	OrgID    string `json:"org_id" src:"query" desc:"组织ID筛选"`
}

// ListClientsResponse 客户端列表响应
type ListClientsResponse struct {
	Items      []ClientResponse `json:"items"`
	Total      int64            `json:"total"`
	Page       int              `json:"page"`
	PageSize   int              `json:"page_size"`
	TotalPages int              `json:"total_pages"`
}

// ListClients 获取OAuth客户端列表
func ListClients(x *vigo.X, req *ListClientsRequest) (*ListClientsResponse, error) {
	userID := middleware.CurrentUser(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	if req.Page < 1 {
		req.Page = 1
	}
	if req.PageSize < 1 || req.PageSize > 100 {
		req.PageSize = 10
	}

	query := model.DB.Model(&model.OAuthClient{}).Where("owner_id = ? OR org_id IN (SELECT org_id FROM org_members WHERE user_id = ? AND status = ?)", userID, userID, model.MemberStatusActive)
	if req.OrgID != "" {
		query = query.Where("org_id = ?", req.OrgID)
	}

	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	var clients []model.OAuthClient
	offset := (req.Page - 1) * req.PageSize
	if err := query.Offset(offset).Limit(req.PageSize).Order("created_at DESC").Find(&clients).Error; err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	items := make([]ClientResponse, 0, len(clients))
	for _, c := range clients {
		items = append(items, toClientResponse(&c, false))
	}

	totalPages := int((total + int64(req.PageSize) - 1) / int64(req.PageSize))
	return &ListClientsResponse{
		Items:      items,
		Total:      total,
		Page:       req.Page,
		PageSize:   req.PageSize,
		TotalPages: totalPages,
	}, nil
}

// GetClientRequest 获取客户端请求
type GetClientRequest struct {
	ID string `json:"id" src:"path@client_id" desc:"客户端ID"`
}

// GetClient 获取客户端详情
func GetClient(x *vigo.X, req *GetClientRequest) (*ClientResponse, error) {
	userID := middleware.CurrentUser(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	var client model.OAuthClient
	if err := model.DB.Where("client_id = ?", req.ID).First(&client).Error; err != nil {
		return nil, vigo.ErrNotFound
	}

	// 检查权限
	if client.OwnerID != userID {
		// 检查是否是组织成员
		if client.OrgID != "" {
			var member model.OrgMember
			if err := model.DB.Where("org_id = ? AND user_id = ? AND status = ?", client.OrgID, userID, model.MemberStatusActive).First(&member).Error; err != nil {
				return nil, vigo.ErrForbidden
			}
		} else {
			return nil, vigo.ErrForbidden
		}
	}

	resp := toClientResponse(&client, false)
	return &resp, nil
}

// UpdateClientRequest 更新客户端请求
type UpdateClientRequest struct {
	ID            string   `json:"id" src:"path@client_id" desc:"客户端ID"`
	Name          *string  `json:"name" src:"json" desc:"应用名称"`
	Description   *string  `json:"description" src:"json" desc:"应用描述"`
	RedirectURIs  []string `json:"redirect_uris" src:"json" desc:"回调地址列表"`
	AllowedScopes []string `json:"allowed_scopes" src:"json" desc:"允许的权限范围"`
	TokenExpiry   *int     `json:"token_expiry" src:"json" desc:"Token有效期"`
	RefreshExpiry *int     `json:"refresh_expiry" src:"json" desc:"RefreshToken有效期"`
	Status        *int     `json:"status" src:"json" desc:"状态"`
}

// UpdateClient 更新OAuth客户端
func UpdateClient(x *vigo.X, req *UpdateClientRequest) (*ClientResponse, error) {
	userID := middleware.CurrentUser(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	var client model.OAuthClient
	if err := model.DB.Where("client_id = ?", req.ID).First(&client).Error; err != nil {
		return nil, vigo.ErrNotFound
	}

	// 检查权限
	if client.OwnerID != userID {
		if client.OrgID != "" {
			var member model.OrgMember
			if err := model.DB.Where("org_id = ? AND user_id = ? AND status = ?", client.OrgID, userID, model.MemberStatusActive).First(&member).Error; err != nil {
				return nil, vigo.ErrForbidden
			}
		} else {
			return nil, vigo.ErrForbidden
		}
	}

	updates := make(map[string]interface{})
	if req.Name != nil {
		updates["name"] = *req.Name
	}
	if req.Description != nil {
		updates["description"] = *req.Description
	}
	if req.RedirectURIs != nil {
		updates["redirect_uris"] = strings.Join(req.RedirectURIs, ",")
	}
	if req.AllowedScopes != nil {
		updates["allowed_scopes"] = strings.Join(req.AllowedScopes, ",")
	}
	if req.TokenExpiry != nil {
		updates["token_expiry"] = *req.TokenExpiry
	}
	if req.RefreshExpiry != nil {
		updates["refresh_expiry"] = *req.RefreshExpiry
	}
	if req.Status != nil {
		updates["status"] = *req.Status
	}

	if len(updates) > 0 {
		if err := model.DB.Model(&client).Updates(updates).Error; err != nil {
			return nil, vigo.ErrInternalServer.WithError(err)
		}
	}

	// 重新获取
	model.DB.First(&client, "client_id = ?", req.ID)
	resp := toClientResponse(&client, false)
	return &resp, nil
}

// DeleteClientRequest 删除客户端请求
type DeleteClientRequest struct {
	ID string `json:"id" src:"path@client_id" desc:"客户端ID"`
}

// DeleteClient 删除OAuth客户端
func DeleteClient(x *vigo.X, req *DeleteClientRequest) error {
	userID := middleware.CurrentUser(x)
	if userID == "" {
		return vigo.ErrNotAuthorized
	}

	var client model.OAuthClient
	if err := model.DB.Where("client_id = ?", req.ID).First(&client).Error; err != nil {
		return vigo.ErrNotFound
	}

	// 检查权限
	if client.OwnerID != userID {
		if client.OrgID != "" {
			var member model.OrgMember
			if err := model.DB.Where("org_id = ? AND user_id = ? AND status = ?", client.OrgID, userID, model.MemberStatusActive).First(&member).Error; err != nil {
				return vigo.ErrForbidden
			}
		} else {
			return vigo.ErrForbidden
		}
	}

	// 软删除
	if err := model.DB.Delete(&client).Error; err != nil {
		return vigo.ErrInternalServer.WithError(err)
	}

	return nil
}

// RegenerateSecretRequest 重新生成密钥请求
type RegenerateSecretRequest struct {
	ID string `json:"id" src:"path@client_id" desc:"客户端ID"`
}

// RegenerateSecret 重新生成客户端密钥
func RegenerateSecret(x *vigo.X, req *RegenerateSecretRequest) (*ClientResponse, error) {
	userID := middleware.CurrentUser(x)
	if userID == "" {
		return nil, vigo.ErrNotAuthorized
	}

	var client model.OAuthClient
	if err := model.DB.Where("client_id = ?", req.ID).First(&client).Error; err != nil {
		return nil, vigo.ErrNotFound
	}

	// 检查权限
	if client.OwnerID != userID {
		if client.OrgID != "" {
			var member model.OrgMember
			if err := model.DB.Where("org_id = ? AND user_id = ? AND status = ?", client.OrgID, userID, model.MemberStatusActive).First(&member).Error; err != nil {
				return nil, vigo.ErrForbidden
			}
		} else {
			return nil, vigo.ErrForbidden
		}
	}

	// 生成新密钥
	newSecret := generateClientSecret()
	if err := model.DB.Model(&client).Update("client_secret", newSecret).Error; err != nil {
		return nil, vigo.ErrInternalServer.WithError(err)
	}

	resp := toClientResponse(&client, true)
	return &resp, nil
}

// helper functions
func toClientResponse(c *model.OAuthClient, includeSecret bool) ClientResponse {
	resp := ClientResponse{
		ID:            c.ID,
		Name:          c.Name,
		Description:   c.Description,
		ClientID:      c.ClientID,
		RedirectURIs:  strings.Split(c.RedirectURIs, ","),
		GrantTypes:    strings.Split(c.GrantTypes, ","),
		ResponseTypes: strings.Split(c.ResponseTypes, ","),
		AllowedScopes: strings.Split(c.AllowedScopes, ","),
		TokenExpiry:   c.TokenExpiry,
		RefreshExpiry: c.RefreshExpiry,
		OwnerID:       c.OwnerID,
		OrgID:         c.OrgID,
		Status:        c.Status,
		CreatedAt:     c.CreatedAt.Format("2006-01-02 15:04:05"),
	}
	if includeSecret {
		resp.ClientSecret = c.ClientSecret
	}
	return resp
}
