package domain

import (
	"time"

	"github.com/google/uuid"
)

// SessionStatus represents the status of a user session
type SessionStatus string

const (
	SessionStatusActive    SessionStatus = "active"
	SessionStatusExpired   SessionStatus = "expired"
	SessionStatusRevoked   SessionStatus = "revoked"
	SessionStatusSuspended SessionStatus = "suspended"
)

// SessionType represents the type of session
type SessionType string

const (
	SessionTypeWeb    SessionType = "web"
	SessionTypeMobile SessionType = "mobile"
	SessionTypeAPI    SessionType = "api"
)

// UserSession represents a user session in the system
type UserSession struct {
	ID           uuid.UUID     `json:"id" db:"id"`
	UserID       string        `json:"user_id" validate:"required" db:"user_id"`
	AppID        string        `json:"app_id" validate:"required" db:"app_id"`
	SessionType  SessionType   `json:"session_type" validate:"required,oneof=web mobile api" db:"session_type"`
	Status       SessionStatus `json:"status" validate:"required,oneof=active expired revoked suspended" db:"status"`
	AccessToken  string        `json:"-" db:"access_token"`  // Hidden from JSON for security
	RefreshToken string        `json:"-" db:"refresh_token"` // Hidden from JSON for security
	IDToken      string        `json:"-" db:"id_token"`      // Hidden from JSON for security
	IPAddress    string        `json:"ip_address" db:"ip_address"`
	UserAgent    string        `json:"user_agent" db:"user_agent"`
	LastActivity time.Time     `json:"last_activity" db:"last_activity"`
	ExpiresAt    time.Time     `json:"expires_at" db:"expires_at"`
	CreatedAt    time.Time     `json:"created_at" db:"created_at"`
	UpdatedAt    time.Time     `json:"updated_at" db:"updated_at"`
	RevokedAt    *time.Time    `json:"revoked_at,omitempty" db:"revoked_at"`
	RevokedBy    *string       `json:"revoked_by,omitempty" db:"revoked_by"`
	Metadata     SessionMetadata `json:"metadata" db:"metadata"`
}

// SessionMetadata contains additional session information
type SessionMetadata struct {
	DeviceInfo    string            `json:"device_info,omitempty"`
	Location      string            `json:"location,omitempty"`
	LoginMethod   string            `json:"login_method,omitempty"`
	TenantID      string            `json:"tenant_id,omitempty"`
	Permissions   []string          `json:"permissions,omitempty"`
	Claims        map[string]string `json:"claims,omitempty"`
	RefreshCount  int               `json:"refresh_count"`
	LastRefresh   *time.Time        `json:"last_refresh,omitempty"`
}

// CreateSessionRequest represents a request to create a new session
type CreateSessionRequest struct {
	UserID      string            `json:"user_id" validate:"required"`
	AppID       string            `json:"app_id" validate:"required"`
	SessionType SessionType       `json:"session_type" validate:"required,oneof=web mobile api"`
	IPAddress   string            `json:"ip_address" validate:"required,ip"`
	UserAgent   string            `json:"user_agent" validate:"required"`
	ExpiresAt   time.Time         `json:"expires_at" validate:"required"`
	Permissions []string          `json:"permissions,omitempty"`
	Claims      map[string]string `json:"claims,omitempty"`
	TenantID    string            `json:"tenant_id,omitempty"`
}

// UpdateSessionRequest represents a request to update a session
type UpdateSessionRequest struct {
	Status       *SessionStatus `json:"status,omitempty" validate:"omitempty,oneof=active expired revoked suspended"`
	LastActivity *time.Time     `json:"last_activity,omitempty"`
	ExpiresAt    *time.Time     `json:"expires_at,omitempty"`
	IPAddress    *string        `json:"ip_address,omitempty" validate:"omitempty,ip"`
	UserAgent    *string        `json:"user_agent,omitempty"`
}

// SessionListRequest represents a request to list sessions
type SessionListRequest struct {
	UserID      string         `json:"user_id,omitempty"`
	AppID       string         `json:"app_id,omitempty"`
	Status      *SessionStatus `json:"status,omitempty"`
	SessionType *SessionType   `json:"session_type,omitempty"`
	TenantID    string         `json:"tenant_id,omitempty"`
	Limit       int            `json:"limit" validate:"min=1,max=100"`
	Offset      int            `json:"offset" validate:"min=0"`
}

// SessionListResponse represents a response for listing sessions
type SessionListResponse struct {
	Sessions []*UserSession `json:"sessions"`
	Total    int            `json:"total"`
	Limit    int            `json:"limit"`
	Offset   int            `json:"offset"`
}

// IsActive checks if the session is currently active
func (s *UserSession) IsActive() bool {
	return s.Status == SessionStatusActive && time.Now().Before(s.ExpiresAt)
}

// IsExpired checks if the session has expired
func (s *UserSession) IsExpired() bool {
	return time.Now().After(s.ExpiresAt) || s.Status == SessionStatusExpired
}

// IsRevoked checks if the session has been revoked
func (s *UserSession) IsRevoked() bool {
	return s.Status == SessionStatusRevoked
}

// CanRefresh checks if the session can be refreshed
func (s *UserSession) CanRefresh() bool {
	return s.IsActive() && s.RefreshToken != ""
}

// UpdateActivity updates the last activity timestamp
func (s *UserSession) UpdateActivity() {
	s.LastActivity = time.Now()
	s.UpdatedAt = time.Now()
}

// Revoke marks the session as revoked
func (s *UserSession) Revoke(revokedBy string) {
	now := time.Now()
	s.Status = SessionStatusRevoked
	s.RevokedAt = &now
	s.RevokedBy = &revokedBy
	s.UpdatedAt = now
}

// Expire marks the session as expired
func (s *UserSession) Expire() {
	s.Status = SessionStatusExpired
	s.UpdatedAt = time.Now()
}

// Suspend marks the session as suspended
func (s *UserSession) Suspend() {
	s.Status = SessionStatusSuspended
	s.UpdatedAt = time.Now()
}

// Activate marks the session as active
func (s *UserSession) Activate() {
	s.Status = SessionStatusActive
	s.UpdatedAt = time.Now()
}
