package particle

import (
	"encoding/json"
	"errors"
	"time"
)

// ParticleType represents the type of particle
type ParticleType string

const (
	TypeStream ParticleType = "stream"
	TypeFolder ParticleType = "folder"
	TypeMedia  ParticleType = "media"
	TypeFile   ParticleType = "file"
	TypeText   ParticleType = "text"
	TypeQuest  ParticleType = "quest"
	TypePaper  ParticleType = "paper"
	// TypeThink  ParticleType = "think"
)

// VisibilityMode represents how access to a particle is determined
type VisibilityMode string

const (
	VisibilityNetworkAll VisibilityMode = "network_all"
	VisibilityCustom     VisibilityMode = "custom"
	VisibilityInherited  VisibilityMode = "inherited"
)

var ErrInvalidParticleType = errors.New("invalid particle type")
var ErrInvalidVisibilityMode = errors.New("invalid visibility mode")

// ParseParticleType parses a string into a ParticleType
func ParseParticleType(s string) (ParticleType, error) {
	switch s {
	case string(TypeStream):
		return TypeStream, nil
	case string(TypeFolder):
		return TypeFolder, nil
	case string(TypeMedia):
		return TypeMedia, nil
	case string(TypeFile):
		return TypeFile, nil
	case string(TypeText):
		return TypeText, nil
	case string(TypeQuest):
		return TypeQuest, nil
	case string(TypePaper):
		return TypePaper, nil
	default:
		return "", ErrInvalidParticleType
	}
}

// ParseVisibilityMode parses a string into a VisibilityMode
func ParseVisibilityMode(s string) (VisibilityMode, error) {
	switch s {
	case "", string(VisibilityNetworkAll):
		return VisibilityNetworkAll, nil
	case string(VisibilityCustom):
		return VisibilityCustom, nil
	case string(VisibilityInherited):
		return VisibilityInherited, nil
	default:
		return "", ErrInvalidVisibilityMode
	}
}

// Stream status values
type StreamStatus string

const (
	StreamStatusOpen   StreamStatus = "open"
	StreamStatusClosed StreamStatus = "closed"
)

// Particle represents a content particle in the system
type Particle struct {
	ID             string
	Type           ParticleType
	NetworkID      string
	ParentID       *string
	CreatedByEmail string
	Visibility     VisibilityMode
	Data           json.RawMessage
	UpdatedAt      time.Time
	CreatedAt      time.Time
}

// CreateInput represents the input for creating a new particle
type CreateInput struct {
	Type       ParticleType
	NetworkID  string
	ParentID   *string
	Data       json.RawMessage
	Members    []string // Only used when visibility is custom
	Visibility VisibilityMode
}

// ListFilter represents filtering options for listing particles
type ListFilter struct {
	Types []ParticleType
}

// Cursor represents a pagination cursor for bidirectional pagination
type Cursor struct {
	Position  string // particle ID or timestamp
	Direction string // "before" or "after"
}

// ParticleList represents a paginated list of particles
type ParticleList struct {
	Particles  []*Particle
	HasMore    bool
	NextCursor *Cursor
	PrevCursor *Cursor
}

// StreamData represents the data stored for stream particles
type StreamData struct {
	Name        string  `json:"name"`
	Status      string  `json:"status"` // "open" or "closed"
	Description *string `json:"description"`
}

// FolderData represents the data stored for folder particles
type FolderData struct {
	Name  string  `json:"name"`
	Color *string `json:"color"`
}

// MediaData represents the data stored for media particles
type MediaData struct {
	ObjectID   string `json:"object_id"` // reference to storage object
	MimeType   string `json:"mime_type"`
	DurationMs int    `json:"duration_ms"`
	// Caption    *string `json:"caption"`
}

// FileData represents the data stored for file particles
type FileData struct {
	ObjectID string `json:"object_id"` // reference to storage object
	Filename string `json:"filename"`
	MimeType string `json:"mime_type"`
	Size     int64  `json:"size"` // in bytes
}

// TextData represents the data stored for text particles
type TextData struct {
	Content string `json:"content"`
}

// QuestData represents the data stored for quest particles
type QuestData struct {
	Title       string  `json:"title"`
	Description string  `json:"description"`
	Done        bool    `json:"done"`
	Status      *string `json:"status"`
	AssignedTo  *string `json:"assigned_to,omitempty"` // email
	DueDate     *string `json:"due_date,omitempty"`    // ISO date string
}

// PaperData represents the data stored for paper particles
type PaperData struct {
	Title   string `json:"title"`
	Content string `json:"content"` // markdown
}

// AckInfo represents an acknowledgment record
type AckInfo struct {
	Email   string
	AckedAt time.Time
}
