package models

import (
	"encoding/json"
	"time"

	"github.com/google/uuid"
)

// RealtimeEventType represents the type of realtime event
type RealtimeEventType string

const (
	// Campaign events
	EventCampaignStatus   RealtimeEventType = "campaign.status"
	EventCampaignProgress RealtimeEventType = "campaign.progress"
	EventCampaignLog      RealtimeEventType = "campaign.log"

	// Email account events
	EventEmailError  RealtimeEventType = "email.error"
	EventEmailStatus RealtimeEventType = "email.status"

	// Task events
	EventTaskStatus RealtimeEventType = "task.status"

	// Contact events
	EventContactChanged RealtimeEventType = "contact.changed"

	// Warmup events
	EventWarmupProgress RealtimeEventType = "warmup.progress"
	EventWarmupBlocked  RealtimeEventType = "warmup.blocked"

	// Worker events
	EventWorkerStatus RealtimeEventType = "worker.status"

	// Inbox events
	EventInboxNew    RealtimeEventType = "inbox.new"
	EventInboxUpdate RealtimeEventType = "inbox.update"

	// Analytics events
	EventAnalyticsEmailOpen  RealtimeEventType = "analytics.email_open"
	EventAnalyticsEmailClick RealtimeEventType = "analytics.email_click"
	EventAnalyticsEmailReply RealtimeEventType = "analytics.email_reply"
	EventAnalyticsBounce     RealtimeEventType = "analytics.email_bounce"

	// Meetings (booked / rescheduled / canceled via Calendly / Cal.com). Drives
	// live updates on the Meetings page, the contact timeline, and the sidebar.
	EventMeetingBooked      RealtimeEventType = "meeting.booked"
	EventMeetingRescheduled RealtimeEventType = "meeting.rescheduled"
	EventMeetingCanceled    RealtimeEventType = "meeting.canceled"
)

// RealtimeEventPriority represents the priority of realtime events
type RealtimeEventPriority string

const (
	PriorityCritical RealtimeEventPriority = "critical"
	PriorityNormal   RealtimeEventPriority = "normal"
)

// CriticalEvents are events that should be persisted for catch-up
var CriticalEvents = map[RealtimeEventType]bool{
	EventEmailError:     true,
	EventEmailStatus:    true,
	EventCampaignStatus: true,
	EventWarmupBlocked:  true,
}

// RealtimeMessage is the base message format sent over WebSocket
type RealtimeMessage struct {
	Type      RealtimeEventType `json:"type"`
	Topic     string            `json:"topic,omitempty"`
	Payload   json.RawMessage   `json:"payload"`
	Timestamp time.Time         `json:"timestamp"`
}

// ClientMessage represents messages from client to server
type ClientMessage struct {
	Action string   `json:"action"` // "subscribe" | "unsubscribe" | "ping"
	Topics []string `json:"topics,omitempty"`
}

// SubscriptionResponse is sent when subscription changes
type SubscriptionResponse struct {
	Action  string   `json:"action"` // "subscribed" | "unsubscribed"
	Topics  []string `json:"topics"`
	Success bool     `json:"success"`
	Error   string   `json:"error,omitempty"`
}

// ConnectionInfo is sent when a client connects
type ConnectionInfo struct {
	ConnectionID string   `json:"connection_id"`
	Topics       []string `json:"available_topics"`
}

// CampaignStatusPayload for campaign status events
type CampaignStatusPayload struct {
	CampaignID uuid.UUID `json:"campaign_id"`
	Status     string    `json:"status"`
	PrevStatus string    `json:"prev_status,omitempty"`
	Timestamp  time.Time `json:"timestamp"`
}

// CampaignProgressPayload for campaign progress events
type CampaignProgressPayload struct {
	CampaignID     uuid.UUID `json:"campaign_id"`
	Sent           int       `json:"sent"`
	Pending        int       `json:"pending"`
	Failed         int       `json:"failed"`
	Delivered      int       `json:"delivered"`
	Opened         int       `json:"opened"`
	Clicked        int       `json:"clicked"`
	Replied        int       `json:"replied"`
	Bounced        int       `json:"bounced"`
	Unsubscribed   int       `json:"unsubscribed"`
	TotalContacts  int       `json:"total_contacts"`
	CompletionPct  float64   `json:"completion_pct"`
	LastActivityAt time.Time `json:"last_activity_at"`
}

// CampaignLogPayload for campaign log events
type CampaignLogPayload struct {
	CampaignID uuid.UUID `json:"campaign_id"`
	LogType    string    `json:"log_type"` // "info" | "warning" | "error"
	Message    string    `json:"message"`
	Metadata   any       `json:"metadata,omitempty"`
	Timestamp  time.Time `json:"timestamp"`
}

// EmailErrorPayload for email account error events
type EmailErrorPayload struct {
	AccountID   uuid.UUID `json:"account_id"`
	ErrorType   string    `json:"error_type"` // "auth_error" | "rate_limit" | "disabled" | "bounce_rate"
	Message     string    `json:"message"`
	Recoverable bool      `json:"recoverable"`
	Timestamp   time.Time `json:"timestamp"`
}

// EmailStatusPayload for email account status events
type EmailStatusPayload struct {
	AccountID   uuid.UUID `json:"account_id"`
	Status      string    `json:"status"` // "healthy" | "warning" | "error" | "disabled"
	HealthScore int       `json:"health_score"`
	Message     string    `json:"message,omitempty"`
	Timestamp   time.Time `json:"timestamp"`
}

// TaskStatusPayload for task lifecycle events
type TaskStatusPayload struct {
	TaskID     uuid.UUID  `json:"task_id"`
	CampaignID *uuid.UUID `json:"campaign_id,omitempty"`
	Status     string     `json:"status"` // "pending" | "processing" | "completed" | "failed"
	Error      string     `json:"error,omitempty"`
	Timestamp  time.Time  `json:"timestamp"`
}

// ContactChangedPayload for contact change events
type ContactChangedPayload struct {
	ContactID  uuid.UUID `json:"contact_id"`
	CampaignID uuid.UUID `json:"campaign_id"`
	Action     string    `json:"action"` // "added" | "updated" | "removed"
	Timestamp  time.Time `json:"timestamp"`
}

// WarmupProgressPayload for warmup progress events
type WarmupProgressPayload struct {
	AccountID   uuid.UUID `json:"account_id"`
	DailySent   int       `json:"daily_sent"`
	DailyTarget int       `json:"daily_target"`
	TotalSent   int       `json:"total_sent"`
	WarmupDays  int       `json:"warmup_days"`
	HealthScore int       `json:"health_score"`
	ReplyRate   float64   `json:"reply_rate"`
	Timestamp   time.Time `json:"timestamp"`
}

// WarmupBlockedPayload for warmup blocked events
type WarmupBlockedPayload struct {
	AccountID uuid.UUID `json:"account_id"`
	Reason    string    `json:"reason"`
	BlockedAt time.Time `json:"blocked_at"`
}

// WorkerStatusPayload for worker status events
type WorkerStatusPayload struct {
	WorkerID     uuid.UUID `json:"worker_id"`
	Status       string    `json:"status"` // "online" | "offline" | "maintenance"
	AccountCount int       `json:"account_count"`
	Timestamp    time.Time `json:"timestamp"`
}

// InboxNewPayload for new inbox email events
type InboxNewPayload struct {
	EmailID   uuid.UUID `json:"email_id"`
	AccountID uuid.UUID `json:"account_id"`
	From      string    `json:"from"`
	Subject   string    `json:"subject"`
	Snippet   string    `json:"snippet"`
	ThreadID  string    `json:"thread_id,omitempty"`
	Timestamp time.Time `json:"timestamp"`
}

// InboxUpdatePayload for inbox update events
type InboxUpdatePayload struct {
	EmailID   uuid.UUID `json:"email_id"`
	AccountID uuid.UUID `json:"account_id"`
	Flags     []string  `json:"flags"` // "read" | "starred" | "archived"
	Timestamp time.Time `json:"timestamp"`
}

// AnalyticsEventPayload for analytics events (open, click, reply, bounce)
type AnalyticsEventPayload struct {
	CampaignID uuid.UUID  `json:"campaign_id"`
	ContactID  uuid.UUID  `json:"contact_id"`
	EmailID    *uuid.UUID `json:"email_id,omitempty"`
	Link       string     `json:"link,omitempty"`   // For click events
	Reason     string     `json:"reason,omitempty"` // For bounce events
	Timestamp  time.Time  `json:"timestamp"`
}

// RealtimeEvent represents a persisted realtime event (for catch-up)
type RealtimeEvent struct {
	ID        uuid.UUID             `json:"id"`
	UserID    uuid.UUID             `json:"user_id"`
	OrgID     *uuid.UUID            `json:"org_id,omitempty"`
	EventType RealtimeEventType     `json:"event_type"`
	Priority  RealtimeEventPriority `json:"priority"`
	Payload   json.RawMessage       `json:"payload"`
	Delivered bool                  `json:"delivered"`
	CreatedAt time.Time             `json:"created_at"`
	ExpiresAt time.Time             `json:"expires_at"`
}

// TopicFormat defines topic naming patterns
const (
	TopicUser     = "user:%s"     // user:{userID}
	TopicOrg      = "org:%s"      // org:{orgID}
	TopicCampaign = "campaign:%s" // campaign:{campaignID}
	TopicAccount  = "account:%s"  // account:{accountID}
	TopicInbox    = "inbox:%s"    // inbox:{accountID}
)

// WebSocketToken represents a token for WebSocket authentication
type WebSocketToken struct {
	Token     string    `json:"token"`
	UserID    uuid.UUID `json:"user_id"`
	OrgID     uuid.UUID `json:"org_id"`
	ExpiresAt time.Time `json:"expires_at"`
}

// RealtimeInfo contains WebSocket connection information
type RealtimeInfo struct {
	WebSocketURL string   `json:"websocket_url"`
	Topics       []string `json:"topics"`
	MaxRetries   int      `json:"max_retries"`
	RetryDelayMs int      `json:"retry_delay_ms"`
}
