package oauth2

import (
	"errors"
	"github.com/tidbcloud/auth-server/internal/entity"
	"strconv"
	"time"
)

type TokenRequest struct {
	GrantType string `form:"grant_type" json:"grant_type"`

	ClientID     string `form:"client_id" json:"client_id"`
	ClientSecret string `form:"client_secret" json:"client_secret"`

	DeviceCode   string `form:"device_code" json:"device_code"`
	Code         string `form:"code" json:"code"`
	RedirectURI  string `form:"redirect_uri" json:"redirect_uri"`
	RefreshToken string `form:"refresh_token" json:"refresh_token"`
}

func (r *TokenRequest) Validate() error {
	if r.GrantType == "" {
		return errors.New("grant_type is required")
	}
	return nil
}

func (r *TokenRequest) ValidateDeviceGrant() error {
	if r.DeviceCode == "" {
		return errors.New("device_code is required")
	}
	if r.ClientID == "" {
		return errors.New("client_id is required")
	}
	return nil
}

func (r *TokenRequest) ValidateCodeGrant() error {
	if r.Code == "" {
		return errors.New("code is required")
	}
	if r.ClientID == "" {
		return errors.New("client_id is required")
	}
	if r.ClientSecret == "" {
		return errors.New("client_secret is required")
	}
	if r.RedirectURI == "" {
		return errors.New("redirect_uri is required")
	}
	return nil
}

func (r *TokenRequest) ValidateRefreshToken() error {
	if r.RefreshToken == "" {
		return errors.New("refresh_token is required")
	}
	if r.ClientID == "" {
		return errors.New("client_id is required")
	}
	if r.ClientSecret == "" {
		return errors.New("client_secret is required")
	}
	return nil
}

// Only used for generating swagger doc
type DeviceTokenRequest struct {
	GrantType  string `form:"grant_type" json:"grant_type"`
	DeviceCode string `form:"device_code" json:"device_code"`
	ClientID   string `form:"client_id" json:"client_id"`
}

// Only used for generating swagger doc
type RefreshTokenRequest struct {
	GrantType    string `form:"grant_type" json:"grant_type"`
	RefreshToken string `form:"refresh_token" json:"refresh_token"`
	ClientID     string `form:"client_id" json:"client_id"`
	ClientSecret string `form:"client_secret" json:"client_secret"`
}

// Only used for generating swagger doc
type AuthorizationCodeTokenRequest struct {
	GrantType    string `form:"grant_type" json:"grant_type"`
	ClientID     string `form:"client_id" json:"client_id"`
	ClientSecret string `form:"client_secret" json:"client_secret"`
	RedirectURI  string `form:"redirect_uri" json:"redirect_uri"`
	Code         string `form:"code" json:"code"`
}

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in,omitempty"`
	RefreshToken string `json:"refresh_token,omitempty"`
}

type RevokeTokenRequest struct {
	ClientID      string `form:"client_id" json:"client_id"`
	ClientSecret  string `form:"client_secret" json:"client_secret"`
	Token         string `form:"token" json:"token"`
	TokenTypeHint string `form:"token_type_hint" json:"token_type_hint"`
}

func (r *RevokeTokenRequest) Validate() error {
	if r.ClientID == "" {
		return errors.New("client_id is required")
	}
	if r.ClientSecret == "" {
		return errors.New("client_secret is required")
	}
	if r.Token == "" {
		return errors.New("token is required")
	}
	if r.TokenTypeHint != "" && r.TokenTypeHint != "access_token" && r.TokenTypeHint != "refresh_token" {
		return errors.New("unsupported token type")
	}
	return nil
}

/*
func (r *ConsoleRevokeTokenRequest) Validate() error {
	if r.ApplicationID == 0 {
		return errors.New("application_id is required")
	}

	if r.TokenTypeHint != "" && r.TokenTypeHint != "access_token" && r.TokenTypeHint != "refresh_token" {
		return errors.New("unsupported token type")
	}
	if r.OrgID != "" {

		parseOrgId, err := strconv.ParseUint(r.OrgID, 10, 64)
		if err != nil {
			return errors.New("org_id is invalid")
		}
		r.parsedOrgID = parseOrgId
	}
	return nil
}
func (r *ConsoleRevokeTokenRequest) GetParsedOrgID() uint64 {

	return r.parsedOrgID
}
*/

// Only used for generating swagger doc
type InnerQueryTokenRequest struct {
	ApplicationID uint64 `form:"application_id" json:"application_id"`
	OrgID         string `form:"org_id" json:"org_id"`
	GrantType     string `form:"grant_type" json:"grant_type"`
	UserID        string `form:"user_id" json:"user_id"`
	UserEmail     string `form:"user_email" json:"user_email"`
	RefreshToken  string `form:"refresh_token" json:"refresh_token"`
	parsedOrgID   uint64
	parsedUserID  uint64
}

func (r *InnerQueryTokenRequest) ValidateQueryToken() error {
	if r.ApplicationID == 0 {
		return errors.New("application_id is required")
	}
	if r.OrgID != "" {
		parseOrgId, err := strconv.ParseUint(r.OrgID, 10, 64)
		if err != nil {
			return errors.New("org_id is invalid")
		}
		r.parsedOrgID = parseOrgId
	}

	return nil
}
func (r *InnerQueryTokenRequest) GetParsedOrgID() uint64 {
	return r.parsedOrgID
}

func (r *InnerQueryTokenRequest) GetParsedUserID() uint64 {
	if r.parsedUserID != 0 {
		return r.parsedUserID
	}
	if r.UserID != "" {
		parseId, _ := strconv.ParseUint(r.UserID, 10, 64)
		r.parsedUserID = parseId

	}
	return r.parsedUserID
}

type InnerQueryTokenResponse struct {
	InnerBasicResponse

	Tokens []InnerQueryToken `json:"tokens,omitempty"`
}
type InnerQueryToken struct {
	ID                      uint64             `json:"id,omitempty"`
	ExpireAt                time.Time          `json:"expire_at,omitempty"`
	OrgID                   string             `json:"org_id,omitempty"`
	Company                 string             `json:"company,omitempty"`
	GrantType               string             `json:"grant_type,omitempty"`
	UserID                  string             `json:"user_id,omitempty"`
	UserEmail               string             `json:"user_email,omitempty"`
	ApplicationID           uint64             `json:"application_id,omitempty"`
	ApplicationName         string             `json:"application_name,omitempty"`
	ApplicationLogoURILight string             `json:"application_logo_uri_light,omitempty"`
	ApplicationLogoURIDark  string             `json:"application_logo_uri_dark,omitempty"`
	Scopes                  entity.Oauth2Scope `json:"scopes,omitempty"`
	CreatedAt               time.Time          `json:"created_at,omitempty"`
}

type InnerGetUserLastTokenResponse struct {
	InnerBasicResponse
	Token InnerQueryToken `json:"token,omitempty"`
}

// Only used for generating swagger doc
type InnerGetUserLastTokenRequest struct {
	ApplicationID uint64 `form:"application_id" json:"application_id"`
}

func (r *InnerGetUserLastTokenRequest) Validate() error {
	if r.ApplicationID == 0 {
		return errors.New("application_id is required")
	}

	return nil
}

// get userinfo by accesstoken
type UserInfo struct {
	FirstName   string `json:"first_name"`
	LastName    string `json:"last_name"`
	Email       string `json:"email"`
	Username    string `json:"username"`
	CompanyName string `json:"company name,omitempty"` // only for tms
	Country     string `json:"country,omitempty"`      // only for tms
}

// get token info
type AccessTokenInfo struct {
	UserId           uint64             `json:"user_id"`
	UserEmail        string             `json:"user_email"`
	OrgId            uint64             `json:"org_id"`
	ProjectIds       []uint64           `json:"project_ids"`
	GrantAllProjects bool               `json:"grant_all_projects"`
	Scopes           entity.Oauth2Scope `json:"scopes"`
	GrantType        string             `json:"grant_type"`
}
