package domain

import (
	"time"

	"github.com/google/uuid"
)

// TenantStatus represents the status of a tenant
type TenantStatus string

const (
	TenantStatusActive    TenantStatus = "active"
	TenantStatusSuspended TenantStatus = "suspended"
	TenantStatusInactive  TenantStatus = "inactive"
)

// Tenant represents a tenant in the multi-tenant system
type Tenant struct {
	ID          uuid.UUID    `json:"id" db:"id"`
	Name        string       `json:"name" validate:"required,min=1,max=255" db:"name"`
	Slug        string       `json:"slug" validate:"required,min=1,max=100,alphanum" db:"slug"`
	Status      TenantStatus `json:"status" validate:"required,oneof=active suspended inactive" db:"status"`
	Domain      string       `json:"domain,omitempty" validate:"omitempty,fqdn" db:"domain"`
	Description string       `json:"description,omitempty" validate:"max=1000" db:"description"`
	Settings    TenantSettings `json:"settings" db:"settings"`
	CreatedAt   time.Time    `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time    `json:"updated_at" db:"updated_at"`
	CreatedBy   string       `json:"created_by" db:"created_by"`
	UpdatedBy   string       `json:"updated_by" db:"updated_by"`
}

// TenantSettings contains tenant-specific configuration
type TenantSettings struct {
	// Authentication settings
	AuthProvider           string            `json:"auth_provider,omitempty"` // oauth2, saml, header
	SAMLSettings          *SAMLSettings     `json:"saml_settings,omitempty"`
	OAuth2Settings        *OAuth2Settings   `json:"oauth2_settings,omitempty"`
	
	// Session settings
	SessionTimeout         Duration          `json:"session_timeout,omitempty"`
	MaxConcurrentSessions  int               `json:"max_concurrent_sessions,omitempty"`
	
	// Security settings
	RequireMFA             bool              `json:"require_mfa"`
	AllowedIPRanges        []string          `json:"allowed_ip_ranges,omitempty"`
	PasswordPolicy         *PasswordPolicy   `json:"password_policy,omitempty"`
	
	// Token settings
	DefaultTokenDuration   Duration          `json:"default_token_duration,omitempty"`
	MaxTokenDuration       Duration          `json:"max_token_duration,omitempty"`
	
	// Feature flags
	Features               map[string]bool   `json:"features,omitempty"`
	
	// Custom attributes
	CustomAttributes       map[string]string `json:"custom_attributes,omitempty"`
}

// SAMLSettings contains SAML-specific configuration for a tenant
type SAMLSettings struct {
	IDPMetadataURL    string `json:"idp_metadata_url,omitempty"`
	SPEntityID        string `json:"sp_entity_id,omitempty"`
	ACSURL           string `json:"acs_url,omitempty"`
	SPPrivateKey     string `json:"sp_private_key,omitempty"`
	SPCertificate    string `json:"sp_certificate,omitempty"`
	AttributeMapping map[string]string `json:"attribute_mapping,omitempty"`
}

// OAuth2Settings contains OAuth2-specific configuration for a tenant
type OAuth2Settings struct {
	ProviderURL    string            `json:"provider_url,omitempty"`
	ClientID       string            `json:"client_id,omitempty"`
	ClientSecret   string            `json:"client_secret,omitempty"`
	Scopes         []string          `json:"scopes,omitempty"`
	AttributeMapping map[string]string `json:"attribute_mapping,omitempty"`
}

// PasswordPolicy defines password requirements for a tenant
type PasswordPolicy struct {
	MinLength        int  `json:"min_length"`
	RequireUppercase bool `json:"require_uppercase"`
	RequireLowercase bool `json:"require_lowercase"`
	RequireNumbers   bool `json:"require_numbers"`
	RequireSymbols   bool `json:"require_symbols"`
	MaxAge           Duration `json:"max_age,omitempty"`
	PreventReuse     int  `json:"prevent_reuse"` // Number of previous passwords to prevent reuse
}

// TenantUser represents a user within a specific tenant
type TenantUser struct {
	ID          uuid.UUID         `json:"id" db:"id"`
	TenantID    uuid.UUID         `json:"tenant_id" validate:"required" db:"tenant_id"`
	UserID      string            `json:"user_id" validate:"required" db:"user_id"`
	Email       string            `json:"email" validate:"required,email" db:"email"`
	Name        string            `json:"name" validate:"required" db:"name"`
	Roles       []string          `json:"roles" db:"roles"`
	Permissions []string          `json:"permissions" db:"permissions"`
	Status      UserStatus        `json:"status" validate:"required,oneof=active inactive suspended" db:"status"`
	Metadata    map[string]string `json:"metadata,omitempty" db:"metadata"`
	CreatedAt   time.Time         `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time         `json:"updated_at" db:"updated_at"`
	LastLoginAt *time.Time        `json:"last_login_at,omitempty" db:"last_login_at"`
}

// UserStatus represents the status of a user within a tenant
type UserStatus string

const (
	UserStatusActive    UserStatus = "active"
	UserStatusInactive  UserStatus = "inactive"
	UserStatusSuspended UserStatus = "suspended"
)

// TenantRole represents a role within a tenant
type TenantRole struct {
	ID          uuid.UUID `json:"id" db:"id"`
	TenantID    uuid.UUID `json:"tenant_id" validate:"required" db:"tenant_id"`
	Name        string    `json:"name" validate:"required,min=1,max=100" db:"name"`
	Description string    `json:"description,omitempty" validate:"max=500" db:"description"`
	Permissions []string  `json:"permissions" db:"permissions"`
	IsSystem    bool      `json:"is_system" db:"is_system"` // System roles cannot be deleted
	CreatedAt   time.Time `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time `json:"updated_at" db:"updated_at"`
	CreatedBy   string    `json:"created_by" db:"created_by"`
	UpdatedBy   string    `json:"updated_by" db:"updated_by"`
}

// CreateTenantRequest represents a request to create a new tenant
type CreateTenantRequest struct {
	Name        string         `json:"name" validate:"required,min=1,max=255"`
	Slug        string         `json:"slug" validate:"required,min=1,max=100,alphanum"`
	Domain      string         `json:"domain,omitempty" validate:"omitempty,fqdn"`
	Description string         `json:"description,omitempty" validate:"max=1000"`
	Settings    TenantSettings `json:"settings,omitempty"`
}

// UpdateTenantRequest represents a request to update a tenant
type UpdateTenantRequest struct {
	Name        *string         `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
	Status      *TenantStatus   `json:"status,omitempty" validate:"omitempty,oneof=active suspended inactive"`
	Domain      *string         `json:"domain,omitempty" validate:"omitempty,fqdn"`
	Description *string         `json:"description,omitempty" validate:"omitempty,max=1000"`
	Settings    *TenantSettings `json:"settings,omitempty"`
}

// CreateTenantUserRequest represents a request to create a user in a tenant
type CreateTenantUserRequest struct {
	TenantID    uuid.UUID         `json:"tenant_id" validate:"required"`
	UserID      string            `json:"user_id" validate:"required"`
	Email       string            `json:"email" validate:"required,email"`
	Name        string            `json:"name" validate:"required"`
	Roles       []string          `json:"roles,omitempty"`
	Permissions []string          `json:"permissions,omitempty"`
	Metadata    map[string]string `json:"metadata,omitempty"`
}

// UpdateTenantUserRequest represents a request to update a tenant user
type UpdateTenantUserRequest struct {
	Email       *string           `json:"email,omitempty" validate:"omitempty,email"`
	Name        *string           `json:"name,omitempty" validate:"omitempty,min=1"`
	Roles       []string          `json:"roles,omitempty"`
	Permissions []string          `json:"permissions,omitempty"`
	Status      *UserStatus       `json:"status,omitempty" validate:"omitempty,oneof=active inactive suspended"`
	Metadata    map[string]string `json:"metadata,omitempty"`
}

// CreateTenantRoleRequest represents a request to create a role in a tenant
type CreateTenantRoleRequest struct {
	TenantID    uuid.UUID `json:"tenant_id" validate:"required"`
	Name        string    `json:"name" validate:"required,min=1,max=100"`
	Description string    `json:"description,omitempty" validate:"max=500"`
	Permissions []string  `json:"permissions,omitempty"`
}

// UpdateTenantRoleRequest represents a request to update a tenant role
type UpdateTenantRoleRequest struct {
	Name        *string  `json:"name,omitempty" validate:"omitempty,min=1,max=100"`
	Description *string  `json:"description,omitempty" validate:"omitempty,max=500"`
	Permissions []string `json:"permissions,omitempty"`
}

// TenantListRequest represents a request to list tenants
type TenantListRequest struct {
	Status *TenantStatus `json:"status,omitempty"`
	Domain string        `json:"domain,omitempty"`
	Limit  int           `json:"limit" validate:"min=1,max=100"`
	Offset int           `json:"offset" validate:"min=0"`
}

// TenantListResponse represents a response for listing tenants
type TenantListResponse struct {
	Tenants []*Tenant `json:"tenants"`
	Total   int       `json:"total"`
	Limit   int       `json:"limit"`
	Offset  int       `json:"offset"`
}

// IsActive checks if the tenant is active
func (t *Tenant) IsActive() bool {
	return t.Status == TenantStatusActive
}

// IsSuspended checks if the tenant is suspended
func (t *Tenant) IsSuspended() bool {
	return t.Status == TenantStatusSuspended
}

// HasFeature checks if a feature is enabled for the tenant
func (t *Tenant) HasFeature(feature string) bool {
	if t.Settings.Features == nil {
		return false
	}
	enabled, exists := t.Settings.Features[feature]
	return exists && enabled
}

// GetAuthProvider returns the authentication provider for the tenant
func (t *Tenant) GetAuthProvider() string {
	if t.Settings.AuthProvider != "" {
		return t.Settings.AuthProvider
	}
	return "header" // default
}

// GetSessionTimeout returns the session timeout for the tenant
func (t *Tenant) GetSessionTimeout() time.Duration {
	if t.Settings.SessionTimeout.Duration > 0 {
		return t.Settings.SessionTimeout.Duration
	}
	return 8 * time.Hour // default
}

// GetMaxConcurrentSessions returns the maximum concurrent sessions for the tenant
func (t *Tenant) GetMaxConcurrentSessions() int {
	if t.Settings.MaxConcurrentSessions > 0 {
		return t.Settings.MaxConcurrentSessions
	}
	return 10 // default
}

// IsActive checks if the tenant user is active
func (tu *TenantUser) IsActive() bool {
	return tu.Status == UserStatusActive
}

// IsSuspended checks if the tenant user is suspended
func (tu *TenantUser) IsSuspended() bool {
	return tu.Status == UserStatusSuspended
}

// HasRole checks if the user has a specific role
func (tu *TenantUser) HasRole(role string) bool {
	for _, r := range tu.Roles {
		if r == role {
			return true
		}
	}
	return false
}

// HasPermission checks if the user has a specific permission
func (tu *TenantUser) HasPermission(permission string) bool {
	for _, p := range tu.Permissions {
		if p == permission {
			return true
		}
	}
	return false
}

// UpdateLastLogin updates the last login timestamp
func (tu *TenantUser) UpdateLastLogin() {
	now := time.Now()
	tu.LastLoginAt = &now
	tu.UpdatedAt = now
}

// IsSystemRole checks if the role is a system role
func (tr *TenantRole) IsSystemRole() bool {
	return tr.IsSystem
}

// HasPermission checks if the role has a specific permission
func (tr *TenantRole) HasPermission(permission string) bool {
	for _, p := range tr.Permissions {
		if p == permission {
			return true
		}
	}
	return false
}

// TenantContext represents the tenant context for a request
type TenantContext struct {
	TenantID   uuid.UUID `json:"tenant_id"`
	TenantSlug string    `json:"tenant_slug"`
	UserID     string    `json:"user_id"`
	Roles      []string  `json:"roles"`
	Permissions []string `json:"permissions"`
}

// MultiTenantAuthContext extends AuthContext with tenant information
type MultiTenantAuthContext struct {
	*AuthContext
	TenantContext *TenantContext `json:"tenant_context,omitempty"`
}
