package entity

import (
	"database/sql/driver"
	"encoding/json"
	"time"
)

//go:generate goqueryset -in entity.go
var Models = []interface{}{
	&RbacRole{}, &RbacPrivilege{}, &RbacRolePrivilege{},
	&Oauth2Application{}, &Oauth2DeviceGrant{}, &Oauth2AccessToken{},
}

// gen:qs
type (
	RbacRole struct {
		Updatable

		Name        string       `gorm:"type:VARCHAR(100);not null" valid:"required"`
		DisplayName string       `gorm:"type:VARCHAR(100);not null"`
		ScopeType   ScopeType    `gorm:"type:VARCHAR(50);not null"`
		Description string       `gorm:"type:VARCHAR(200);not null"`
		Status      EntityStatus `gorm:"type:CHAR(16);not null"`
	}

	RbacPrivilege struct {
		Updatable
		ResourceUri string `gorm:"type:VARCHAR(200);not null"`
		Url         string `gorm:"type:VARCHAR(200);not null"`
		System      string `gorm:"type:VARCHAR(50);not null"`
		Description string `gorm:"type:VARCHAR(200);not null"`
	}

	RbacRolePrivilege struct {
		Updatable
		RbacRoleID      ID `gorm:"not null"`
		RbacPrivilegeID ID `gorm:"not null"`
	}

	Oauth2Application struct {
		Updatable
		Sort                  uint8           `gorm:"type:TINYINT"`
		Name                  string          `gorm:"type:VARCHAR(100);uniqueIndex;not null" valid:"required"`
		Company               string          `gorm:"type:VARCHAR(200)"`
		ClientID              string          `gorm:"type:VARCHAR(100) COLLATE utf8mb4_bin;uniqueIndex;not null" valid:"required"`
		ClientSecret          string          `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;not null" valid:"required"`
		RedirectURI           string          `gorm:"type:VARCHAR(100);not null" valid:"required"`
		GrantType             Oauth2GrantType `gorm:"type:VARCHAR(100);not null" valid:"required"`
		Scopes                Oauth2Scope     `gorm:"type:json;serializer:json;not null"`
		AccessTokenExpiresIn  int             `gorm:"not null;default:7200;comment:the unit is seconds, 0 means never expire"`
		RefreshTokenExpiresIn int             `gorm:"not null;default:0;comment:the unit seconds, 0 means never expire"`
		HomePageURI           string          `gorm:"type:VARCHAR(200);not null"`
		CompanyURI            string          `gorm:"type:VARCHAR(200);not null"`
		LogoURILight          string          `gorm:"type:VARCHAR(200)"`
		LogoURIDark           string          `gorm:"type:VARCHAR(200)"`
		Description           string          `gorm:"type:VARCHAR(200);not null"`
		Type                  ApplicationType `gorm:"type:VARCHAR(100)"`
	}

	Oauth2DeviceGrant struct {
		Updatable
		DeviceCode       string `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;uniqueIndex;not null" valid:"required"`
		UserCode         string `gorm:"type:VARCHAR(10) COLLATE utf8mb4_bin;uniqueIndex;not null" valid:"required"`
		ExpiresIn        int    `gorm:"not null;default:600;comment:the unit is seconds"`
		LastPolledAt     *time.Time
		RevokedAt        *time.Time
		Scopes           string            `gorm:"type:json;not null"`
		ApplicationID    uint64            `gorm:"not null"`
		UserID           uint64            `gorm:"default:null"`
		UserEmail        string            `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;default:null"`
		OrgID            uint64            `gorm:"type:BIGINT;default:null"`
		GrantAllProjects bool              `gorm:"not null;default:false"`
		ProjectIDs       ProjectIDs        `gorm:"type:json;serializer:json;not null"`
		Status           Oauth2GrantStatus `gorm:"not null;default:0"`
		ClientIP         string            `gorm:"type:VARCHAR(50);not null"`
		UserAgent        string            `gorm:"type:VARCHAR(100);not null"`
	}

	Oauth2CodeGrant struct {
		Updatable
		Code          string      `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;uniqueIndex;not null" valid:"required"`
		ExpiresIn     int         `gorm:"not null;default:60;comment:the unit is seconds"`
		RedirectURI   string      `gorm:"type:longtext;not null"`
		Scopes        Oauth2Scope `gorm:"type:json;serializer:json;not null"`
		ApplicationID uint64      `gorm:"not null"`
		UserID        uint64      `gorm:"not null"`
		UserEmail     string      `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;default:null"`
		OrgID         uint64      `gorm:"type:BIGINT;not null"`
		ProjectIDs    ProjectIDs  `gorm:"type:json;serializer:json;not null"`
	}

	Oauth2AccessToken struct {
		Updatable
		AccessToken           string `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;uniqueIndex;not null" valid:"required"`
		AccessTokenExpiresIn  int    `gorm:"not null;default:7200;comment:the unit is seconds, 0 means never expire"`
		RefreshToken          string `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;uniqueIndex"`
		RefreshTokenExpiresIn int    `gorm:"not null;default:0;comment:the unit seconds, 0 means never expire"`
		RevokedAt             *time.Time
		Scopes                Oauth2Scope     `gorm:"type:json;serializer:json;not null"`
		ApplicationID         uint64          `gorm:"not null"`
		UserID                uint64          `gorm:"not null"`
		UserEmail             string          `gorm:"type:VARCHAR(255) COLLATE utf8mb4_bin;not null"`
		OrgID                 uint64          `gorm:"type:BIGINT;not null"`
		GrantAllProjects      bool            `gorm:"not null;default:false"`
		ProjectIDs            ProjectIDs      `gorm:"type:json;serializer:json;not null"`
		GrantType             Oauth2GrantType `gorm:"type:VARCHAR(30);not null;default:'device_code'"`
	}
)

type Oauth2Scope struct {
	Org     string `json:"org"`
	Project string `json:"project"`
}

type ProjectIDs struct {
	IDs []uint64 `json:"ids"`
}

func (c ProjectIDs) Value() (driver.Value, error) {
	b, err := json.Marshal(c)
	return string(b), err
}

// Scan unmarshal json
func (c *ProjectIDs) Scan(input interface{}) error {
	return json.Unmarshal(input.([]byte), c)
}
