package interfaces

import (
	"context"
	"time"

	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
)

// Repository définit l'interface commune pour tous les repositories
type Repository interface {
	// Méthodes communes à tous les repositories
	Ping(ctx context.Context) error
	Close() error
}

// UserRepository définit l'interface pour les opérations utilisateur
type UserRepository interface {
	Repository

	Create(ctx context.Context, user *User) error
	GetByID(ctx context.Context, id string) (*User, error)
	GetByEmail(ctx context.Context, email string) (*User, error)
	GetByUsername(ctx context.Context, username string) (*User, error)
	Update(ctx context.Context, user *User) error
	Delete(ctx context.Context, id string) error
	List(ctx context.Context, limit, offset int) ([]*User, error)
	Count(ctx context.Context) (int64, error)
	Search(ctx context.Context, query string, limit, offset int) ([]*User, error)
}

// MessageRepository définit l'interface pour les opérations de messages
type MessageRepository interface {
	Repository

	Create(ctx context.Context, message *Message) error
	GetByID(ctx context.Context, id string) (*Message, error)
	GetByConversation(ctx context.Context, conversationID string, limit, offset int) ([]*Message, error)
	Update(ctx context.Context, message *Message) error
	Delete(ctx context.Context, id string) error
	MarkAsRead(ctx context.Context, messageID, userID string) error
	GetUnreadCount(ctx context.Context, userID string) (int64, error)
}

// ConversationRepository définit l'interface pour les opérations de conversations
type ConversationRepository interface {
	Repository

	Create(ctx context.Context, conversation *Conversation) error
	GetByID(ctx context.Context, id string) (*Conversation, error)
	GetByUser(ctx context.Context, userID string, limit, offset int) ([]*Conversation, error)
	AddParticipant(ctx context.Context, conversationID, userID string) error
	RemoveParticipant(ctx context.Context, conversationID, userID string) error
	Update(ctx context.Context, conversation *Conversation) error
	Delete(ctx context.Context, id string) error
}

// TrackRepository définit l'interface pour les opérations de tracks
type TrackRepository interface {
	Repository

	Create(ctx context.Context, track *Track) error
	GetByID(ctx context.Context, id string) (*Track, error)
	GetByUser(ctx context.Context, userID string, limit, offset int) ([]*Track, error)
	Update(ctx context.Context, track *Track) error
	Delete(ctx context.Context, id string) error
	Search(ctx context.Context, query string, limit, offset int) ([]*Track, error)
	GetByGenre(ctx context.Context, genre string, limit, offset int) ([]*Track, error)
	GetPopular(ctx context.Context, limit, offset int) ([]*Track, error)
}

// SessionRepository définit l'interface pour les opérations de sessions
type SessionRepository interface {
	Repository

	Create(ctx context.Context, session *Session) error
	GetByToken(ctx context.Context, token string) (*Session, error)
	GetByUser(ctx context.Context, userID string) ([]*Session, error)
	Update(ctx context.Context, session *Session) error
	Delete(ctx context.Context, id string) error
	DeleteByUser(ctx context.Context, userID string) error
	DeleteExpired(ctx context.Context) error
}

// AuditLogRepository définit l'interface pour les logs d'audit
type AuditLogRepository interface {
	Repository

	Create(ctx context.Context, log *AuditLog) error
	GetByUser(ctx context.Context, userID string, limit, offset int) ([]*AuditLog, error)
	GetByAction(ctx context.Context, action string, limit, offset int) ([]*AuditLog, error)
	GetByDateRange(ctx context.Context, start, end time.Time, limit, offset int) ([]*AuditLog, error)
	DeleteOld(ctx context.Context, olderThan time.Time) error
}

// Service définit l'interface commune pour tous les services
type Service interface {
	// Méthodes communes à tous les services
	Health(ctx context.Context) error
	Close() error
}

// AuthService définit l'interface pour les services d'authentification
type AuthService interface {
	Service

	Login(ctx context.Context, email, password string) (*AuthResult, error)
	Register(ctx context.Context, req *RegisterRequest) (*AuthResult, error)
	Logout(ctx context.Context, token string) error
	RefreshToken(ctx context.Context, refreshToken string) (*AuthResult, error)
	ValidateToken(ctx context.Context, token string) (*TokenClaims, error)
	ChangePassword(ctx context.Context, userID, oldPassword, newPassword string) error
	ResetPassword(ctx context.Context, email string) error
	ConfirmPasswordReset(ctx context.Context, token, newPassword string) error
}

// UserService définit l'interface pour les services utilisateur
type UserService interface {
	Service

	Create(ctx context.Context, req *CreateUserRequest) (*User, error)
	GetByID(ctx context.Context, id string) (*User, error)
	GetByEmail(ctx context.Context, email string) (*User, error)
	Update(ctx context.Context, id string, req *UpdateUserRequest) (*User, error)
	Delete(ctx context.Context, id string) error
	List(ctx context.Context, req *ListUsersRequest) (*ListUsersResponse, error)
	Search(ctx context.Context, query string, limit, offset int) ([]*User, error)
	UpdateProfile(ctx context.Context, userID string, req *UpdateProfileRequest) (*User, error)
	UploadAvatar(ctx context.Context, userID string, fileData []byte) (string, error)
}

// MessageService définit l'interface pour les services de messages
type MessageService interface {
	Service

	Send(ctx context.Context, req *SendMessageRequest) (*Message, error)
	GetByID(ctx context.Context, id string) (*Message, error)
	GetByConversation(ctx context.Context, conversationID string, req *ListMessagesRequest) (*ListMessagesResponse, error)
	Update(ctx context.Context, id string, req *UpdateMessageRequest) (*Message, error)
	Delete(ctx context.Context, id string) error
	MarkAsRead(ctx context.Context, messageID, userID string) error
	GetUnreadCount(ctx context.Context, userID string) (int64, error)
	Search(ctx context.Context, query string, userID string, limit, offset int) ([]*Message, error)
}

// ConversationService définit l'interface pour les services de conversations
type ConversationService interface {
	Service

	Create(ctx context.Context, req *CreateConversationRequest) (*Conversation, error)
	GetByID(ctx context.Context, id string) (*Conversation, error)
	GetByUser(ctx context.Context, userID string, req *ListConversationsRequest) (*ListConversationsResponse, error)
	AddParticipant(ctx context.Context, conversationID, userID string) error
	RemoveParticipant(ctx context.Context, conversationID, userID string) error
	Update(ctx context.Context, id string, req *UpdateConversationRequest) (*Conversation, error)
	Delete(ctx context.Context, id string) error
	GetParticipants(ctx context.Context, conversationID string) ([]*User, error)
}

// TrackService définit l'interface pour les services de tracks
type TrackService interface {
	Service

	Upload(ctx context.Context, req *UploadTrackRequest) (*Track, error)
	GetByID(ctx context.Context, id string) (*Track, error)
	GetByUser(ctx context.Context, userID string, req *ListTracksRequest) (*ListTracksResponse, error)
	Update(ctx context.Context, id string, req *UpdateTrackRequest) (*Track, error)
	Delete(ctx context.Context, id string) error
	Search(ctx context.Context, query string, req *SearchTracksRequest) (*SearchTracksResponse, error)
	GetByGenre(ctx context.Context, genre string, limit, offset int) ([]*Track, error)
	GetPopular(ctx context.Context, limit, offset int) ([]*Track, error)
	GetStreamURL(ctx context.Context, trackID string, userID string) (string, error)
}

// CacheService définit l'interface pour les services de cache
type CacheService interface {
	Service

	Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error
	Get(ctx context.Context, key string, dest interface{}) (bool, error)
	Delete(ctx context.Context, key string) error
	ClearByPrefix(ctx context.Context, prefix string) error
	Increment(ctx context.Context, key string) (int64, error)
	Decrement(ctx context.Context, key string) (int64, error)
	Expire(ctx context.Context, key string, ttl time.Duration) error
	Exists(ctx context.Context, key string) (bool, error)
}

// LoggerService définit l'interface pour les services de logging
type LoggerService interface {
	Service

	Debug(msg string, fields ...zap.Field)
	Info(msg string, fields ...zap.Field)
	Warn(msg string, fields ...zap.Field)
	Error(msg string, fields ...zap.Field)
	Fatal(msg string, fields ...zap.Field)

	With(fields ...zap.Field) LoggerService
	WithContext(ctx context.Context) LoggerService
}

// EmailService définit l'interface pour les services d'email
type EmailService interface {
	Service

	SendWelcomeEmail(ctx context.Context, to, username string) error
	SendPasswordResetEmail(ctx context.Context, to, resetToken string) error
	SendPasswordChangedEmail(ctx context.Context, to string) error
	SendEmailVerification(ctx context.Context, to, verificationToken string) error
	SendNotificationEmail(ctx context.Context, to, subject, content string) error
}

// FileService définit l'interface pour les services de fichiers
type FileService interface {
	Service

	Upload(ctx context.Context, req *UploadFileRequest) (*UploadFileResponse, error)
	Download(ctx context.Context, fileID string) (*DownloadFileResponse, error)
	Delete(ctx context.Context, fileID string) error
	GetMetadata(ctx context.Context, fileID string) (*FileMetadata, error)
	GenerateThumbnail(ctx context.Context, fileID string) error
	ScanForViruses(ctx context.Context, filePath string) error
}

// NotificationService définit l'interface pour les services de notifications
type NotificationService interface {
	Service

	SendPushNotification(ctx context.Context, userID, title, body string, data map[string]string) error
	SendInAppNotification(ctx context.Context, userID, message string, data map[string]interface{}) error
	MarkAsRead(ctx context.Context, notificationID, userID string) error
	GetByUser(ctx context.Context, userID string, limit, offset int) ([]*Notification, error)
	GetUnreadCount(ctx context.Context, userID string) (int64, error)
}

// MetricsService définit l'interface pour les services de métriques
type MetricsService interface {
	Service

	IncrementCounter(name string, labels map[string]string)
	IncrementCounterBy(name string, value float64, labels map[string]string)
	SetGauge(name string, value float64, labels map[string]string)
	ObserveHistogram(name string, value float64, labels map[string]string)
	ObserveSummary(name string, value float64, labels map[string]string)

	GetMetrics() (string, error)
}

// ConfigurationService définit l'interface pour les services de configuration
type ConfigurationService interface {
	Service

	GetString(key string) string
	GetInt(key string) int
	GetBool(key string) bool
	GetDuration(key string) time.Duration
	GetStringSlice(key string) []string

	Set(key string, value interface{}) error
	Reload() error
}

// DatabaseService définit l'interface pour les services de base de données
type DatabaseService interface {
	Service

	GetConnection() interface{} // Retourne la connexion spécifique (GORM, SQLx, etc.)
	Ping(ctx context.Context) error
	Close() error
	BeginTx(ctx context.Context) (interface{}, error)
	CommitTx(tx interface{}) error
	RollbackTx(tx interface{}) error

	// Méthodes pour les migrations
	Migrate(ctx context.Context) error
	GetMigrationStatus(ctx context.Context) ([]MigrationStatus, error)
}

// RedisService définit l'interface pour les services Redis
type RedisService interface {
	Service

	GetClient() *redis.Client
	Ping(ctx context.Context) error
	Close() error

	// Méthodes de base
	Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error
	Get(ctx context.Context, key string) (string, error)
	Del(ctx context.Context, keys ...string) error
	Exists(ctx context.Context, keys ...string) (int64, error)
	Expire(ctx context.Context, key string, expiration time.Duration) error

	// Méthodes pour les listes
	LPush(ctx context.Context, key string, values ...interface{}) error
	RPush(ctx context.Context, key string, values ...interface{}) error
	LPop(ctx context.Context, key string) (string, error)
	RPop(ctx context.Context, key string) (string, error)
	LLen(ctx context.Context, key string) (int64, error)

	// Méthodes pour les sets
	SAdd(ctx context.Context, key string, members ...interface{}) error
	SMembers(ctx context.Context, key string) ([]string, error)
	SIsMember(ctx context.Context, key string, member interface{}) (bool, error)
	SCard(ctx context.Context, key string) (int64, error)

	// Méthodes pour les hashs
	HSet(ctx context.Context, key string, values ...interface{}) error
	HGet(ctx context.Context, key, field string) (string, error)
	HGetAll(ctx context.Context, key string) (map[string]string, error)
	HDel(ctx context.Context, key string, fields ...string) error
}
