package domain

import (
	"time"

	"github.com/google/uuid"
)

// ApplicationType represents the type of application
type ApplicationType string

const (
	ApplicationTypeStatic ApplicationType = "static"
	ApplicationTypeUser   ApplicationType = "user"
)

// OwnerType represents the type of owner
type OwnerType string

const (
	OwnerTypeIndividual OwnerType = "individual"
	OwnerTypeTeam       OwnerType = "team"
)

// TokenType represents the type of token
type TokenType string

const (
	TokenTypeStatic TokenType = "static"
	TokenTypeUser   TokenType = "user"
)

// Owner represents ownership information
type Owner struct {
	Type  OwnerType `json:"type" validate:"required,oneof=individual team"`
	Name  string    `json:"name" validate:"required,min=1,max=255"`
	Owner string    `json:"owner" validate:"required,min=1,max=255"`
}

// Application represents an application in the system
type Application struct {
	AppID                string            `json:"app_id" validate:"required,min=1,max=255" db:"app_id"`
	AppLink              string            `json:"app_link" validate:"required,url,max=500" db:"app_link"`
	Type                 []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user" db:"type"`
	CallbackURL          string            `json:"callback_url" validate:"required,url,max=500" db:"callback_url"`
	HMACKey              string            `json:"hmac_key" validate:"required,min=1,max=255" db:"hmac_key"`
	TokenRenewalDuration Duration          `json:"token_renewal_duration" validate:"required,min=1" db:"token_renewal_duration"`
	MaxTokenDuration     Duration          `json:"max_token_duration" validate:"required,min=1" db:"max_token_duration"`
	Owner                Owner             `json:"owner" validate:"required"`
	CreatedAt            time.Time         `json:"created_at" db:"created_at"`
	UpdatedAt            time.Time         `json:"updated_at" db:"updated_at"`
}

// StaticToken represents a static API token
type StaticToken struct {
	ID        uuid.UUID `json:"id" db:"id"`
	AppID     string    `json:"app_id" validate:"required" db:"app_id"`
	Owner     Owner     `json:"owner" validate:"required"`
	KeyHash   string    `json:"-" validate:"required" db:"key_hash"` // Hidden from JSON
	Type      string    `json:"type" validate:"required,eq=hmac" db:"type"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

// AvailablePermission represents a permission in the global catalog
type AvailablePermission struct {
	ID          uuid.UUID  `json:"id" db:"id"`
	Scope       string     `json:"scope" validate:"required,min=1,max=255" db:"scope"`
	Name        string     `json:"name" validate:"required,min=1,max=255" db:"name"`
	Description string     `json:"description" validate:"required" db:"description"`
	Category    string     `json:"category" validate:"required,min=1,max=100" db:"category"`
	ParentScope *string    `json:"parent_scope,omitempty" db:"parent_scope"`
	IsSystem    bool       `json:"is_system" db:"is_system"`
	CreatedAt   time.Time  `json:"created_at" db:"created_at"`
	CreatedBy   string     `json:"created_by" validate:"required" db:"created_by"`
	UpdatedAt   time.Time  `json:"updated_at" db:"updated_at"`
	UpdatedBy   string     `json:"updated_by" validate:"required" db:"updated_by"`
}

// GrantedPermission represents a permission granted to a token
type GrantedPermission struct {
	ID           uuid.UUID `json:"id" db:"id"`
	TokenType    TokenType `json:"token_type" validate:"required,eq=static" db:"token_type"`
	TokenID      uuid.UUID `json:"token_id" validate:"required" db:"token_id"`
	PermissionID uuid.UUID `json:"permission_id" validate:"required" db:"permission_id"`
	Scope        string    `json:"scope" validate:"required" db:"scope"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
	CreatedBy    string    `json:"created_by" validate:"required" db:"created_by"`
	Revoked      bool      `json:"revoked" db:"revoked"`
}

// UserToken represents a user token (JWT-based)
type UserToken struct {
	AppID       string            `json:"app_id"`
	UserID      string            `json:"user_id"`
	Permissions []string          `json:"permissions"`
	IssuedAt    time.Time         `json:"iat"`
	ExpiresAt   time.Time         `json:"exp"`
	MaxValidAt  time.Time         `json:"max_valid_at"`
	TokenType   TokenType         `json:"token_type"`
	Claims      map[string]string `json:"claims,omitempty"`
}

// VerifyRequest represents a token verification request
type VerifyRequest struct {
	AppID       string    `json:"app_id" validate:"required"`
	Type        TokenType `json:"type" validate:"required,oneof=static user"`
	UserID      string    `json:"user_id,omitempty"` // Required for user tokens
	Token       string    `json:"token" validate:"required"`
	Permissions []string  `json:"permissions,omitempty"`
}

// VerifyResponse represents a token verification response
type VerifyResponse struct {
	Valid               bool              `json:"valid"`
	UserID              string            `json:"user_id,omitempty"`
	Permissions         []string          `json:"permissions"`
	PermissionResults   map[string]bool   `json:"permission_results,omitempty"`
	ExpiresAt           *time.Time        `json:"expires_at,omitempty"`
	MaxValidAt          *time.Time        `json:"max_valid_at,omitempty"`
	TokenType           TokenType         `json:"token_type"`
	Claims              map[string]string `json:"claims,omitempty"`
	Error               string            `json:"error,omitempty"`
}

// LoginRequest represents a user login request
type LoginRequest struct {
	AppID       string   `json:"app_id" validate:"required"`
	Permissions []string `json:"permissions,omitempty"`
	RedirectURI string   `json:"redirect_uri,omitempty"`
}

// LoginResponse represents a user login response
type LoginResponse struct {
	RedirectURL string `json:"redirect_url"`
	State       string `json:"state,omitempty"`
}

// RenewRequest represents a token renewal request
type RenewRequest struct {
	AppID  string `json:"app_id" validate:"required"`
	UserID string `json:"user_id" validate:"required"`
	Token  string `json:"token" validate:"required"`
}

// RenewResponse represents a token renewal response
type RenewResponse struct {
	Token      string    `json:"token"`
	ExpiresAt  time.Time `json:"expires_at"`
	MaxValidAt time.Time `json:"max_valid_at"`
	Error      string    `json:"error,omitempty"`
}

// CreateApplicationRequest represents a request to create a new application
type CreateApplicationRequest struct {
	AppID                string            `json:"app_id" validate:"required,min=1,max=255"`
	AppLink              string            `json:"app_link" validate:"required,url,max=500"`
	Type                 []ApplicationType `json:"type" validate:"required,min=1,dive,oneof=static user"`
	CallbackURL          string            `json:"callback_url" validate:"required,url,max=500"`
	TokenRenewalDuration Duration          `json:"token_renewal_duration" validate:"required,min=1"`
	MaxTokenDuration     Duration          `json:"max_token_duration" validate:"required,min=1"`
	Owner                Owner             `json:"owner" validate:"required"`
}

// UpdateApplicationRequest represents a request to update an existing application
type UpdateApplicationRequest struct {
	AppLink              *string            `json:"app_link,omitempty" validate:"omitempty,url,max=500"`
	Type                 *[]ApplicationType `json:"type,omitempty" validate:"omitempty,min=1,dive,oneof=static user"`
	CallbackURL          *string            `json:"callback_url,omitempty" validate:"omitempty,url,max=500"`
	HMACKey              *string            `json:"hmac_key,omitempty" validate:"omitempty,min=1,max=255"`
	TokenRenewalDuration *Duration          `json:"token_renewal_duration,omitempty" validate:"omitempty,min=1"`
	MaxTokenDuration     *Duration          `json:"max_token_duration,omitempty" validate:"omitempty,min=1"`
	Owner                *Owner             `json:"owner,omitempty" validate:"omitempty"`
}

// CreateStaticTokenRequest represents a request to create a static token
type CreateStaticTokenRequest struct {
	AppID       string    `json:"app_id" validate:"required"`
	Owner       Owner     `json:"owner" validate:"required"`
	Permissions []string  `json:"permissions" validate:"required,min=1"`
}

// CreateStaticTokenResponse represents a response for creating a static token
type CreateStaticTokenResponse struct {
	ID          uuid.UUID `json:"id"`
	Token       string    `json:"token"` // Only returned once during creation
	Permissions []string  `json:"permissions"`
	CreatedAt   time.Time `json:"created_at"`
}

// CreateTokenRequest represents a request to create a token
type CreateTokenRequest struct {
	AppID       string            `json:"app_id" validate:"required"`
	Type        TokenType         `json:"type" validate:"required,oneof=static user"`
	UserID      string            `json:"user_id,omitempty"` // Required for user tokens
	Permissions []string          `json:"permissions,omitempty"`
	ExpiresAt   *time.Time        `json:"expires_at,omitempty"`
	Metadata    map[string]string `json:"metadata,omitempty"`
}

// CreateTokenResponse represents a response for creating a token
type CreateTokenResponse struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expires_at"`
	TokenType TokenType `json:"token_type"`
}

// AuthContext represents the authentication context for a request
type AuthContext struct {
	UserID      string            `json:"user_id"`
	TokenType   TokenType         `json:"token_type"`
	Permissions []string          `json:"permissions"`
	Claims      map[string]string `json:"claims"`
	AppID       string            `json:"app_id"`
}

// TokenResponse represents the OAuth2 token response
type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token,omitempty"`
	IDToken      string `json:"id_token,omitempty"`
	Scope        string `json:"scope,omitempty"`
}

// UserInfo represents user information from the OAuth2/OIDC provider
type UserInfo struct {
	Sub               string `json:"sub"`
	Email             string `json:"email"`
	EmailVerified     bool   `json:"email_verified"`
	Name              string `json:"name"`
	GivenName         string `json:"given_name"`
	FamilyName        string `json:"family_name"`
	Picture           string `json:"picture"`
	PreferredUsername string `json:"preferred_username"`
}
