package domain

import (
	"errors"
	"time"
)

var (
	ErrNotFound      = errors.New("studio not found")
	ErrForbidden     = errors.New("studio forbidden")
	ErrValidation    = errors.New("studio validation")
	ErrNoAccount     = errors.New("no usable threads account")
	ErrIllegalStatus = errors.New("illegal outbox status")
	ErrNotDue        = errors.New("step not due")
	ErrRootBlocked   = errors.New("root not published; reply blocked")
	ErrLeaseLost     = errors.New("outbox step lease lost")
	ErrBadURL        = errors.New("invalid external url")
	ErrFormulaRemove = errors.New("generateFromFormula removed")
)

const (
	PersonaEmpty     = "empty"
	PersonaAnalyzing = "analyzing"
	PersonaReady     = "ready"

	PlayDraft      = "draft"
	PlayReady      = "ready"
	PlayScheduling = "scheduling"
	PlayActive     = "active"
	PlayCompleted  = "completed"
	PlayPartial    = "partial_failed"
	PlayArchived   = "archived"

	StepRoot  = "root"
	StepReply = "reply"

	OBScheduling = "scheduling"
	OBActive     = "active"
	OBCompleted  = "completed"
	OBPartial    = "partial_failed"
	OBCancelled  = "cancelled"

	StepDraft      = "draft"
	StepScheduled  = "scheduled"
	StepPublishing = "publishing"
	StepPublished  = "published"
	StepFailed     = "failed"
	StepCancelled  = "cancelled"
	StepBlocked    = "blocked"

	MentionPending = "pending"
	MentionReplied = "replied"
	MentionSkipped = "skipped"
)

func NowNano() int64 { return time.Now().UTC().UnixNano() }

// Persona — PE domain
type Persona struct {
	ID       string       `bson:"_id" json:"id"`
	OwnerUID int64        `bson:"owner_uid" json:"owner_uid"`
	Name     string       `bson:"name" json:"name"`
	Brief    string       `bson:"brief" json:"brief"`
	Status   string       `bson:"status" json:"status"`
	Style    PersonaStyle `bson:"style" json:"style"`
	Guard    PersonaGuard `bson:"guard" json:"guard"`
	Voice    string       `bson:"voice,omitempty" json:"voice,omitempty"`
	Notes    string       `bson:"notes,omitempty" json:"notes,omitempty"`
	// Learning — 資產複利可見（growth-loop）
	LearningSummary       string `bson:"learning_summary,omitempty" json:"learning_summary,omitempty"`
	LearningVersion       int    `bson:"learning_version,omitempty" json:"learning_version,omitempty"`
	LearnedFromPostsCount int    `bson:"learned_from_posts_count,omitempty" json:"learned_from_posts_count,omitempty"`
	LastLearnedAt         int64  `bson:"last_learned_at,omitempty" json:"last_learned_at,omitempty"`
	CreatedAt             int64  `bson:"created_at" json:"created_at"`
	UpdatedAt             int64  `bson:"updated_at" json:"updated_at"`
}

type PersonaStyle struct {
	Draft             PersonaDraft `bson:"draft" json:"draft"`
	DraftText         string       `bson:"draft_text" json:"draft_text"`
	Source            string       `bson:"source" json:"source"` // manual|benchmark|seed
	BenchmarkUsername string       `bson:"benchmark_username,omitempty" json:"benchmark_username,omitempty"`
	SourceLabel       string       `bson:"source_label,omitempty" json:"source_label,omitempty"`
	SampleCount       int          `bson:"sample_count" json:"sample_count"`
	AnalyzedAt        int64        `bson:"analyzed_at,omitempty" json:"analyzed_at,omitempty"`
	SamplePreviews    []string     `bson:"sample_previews,omitempty" json:"sample_previews,omitempty"`
	// Dimensions — 8D 風格摘要（分析後必填，前端「分析」頁卡片）
	Dimensions map[string]StyleDimension `bson:"dimensions,omitempty" json:"dimensions,omitempty"`
}

// StyleDimension — 單一 8D 維度
type StyleDimension struct {
	Summary  string   `bson:"summary" json:"summary"`
	Evidence []string `bson:"evidence,omitempty" json:"evidence,omitempty"`
}

type PersonaDraft struct {
	Identity             string `bson:"identity" json:"identity"`
	Tone                 string `bson:"tone" json:"tone"`
	Audience             string `bson:"audience" json:"audience"`
	Hooks                string `bson:"hooks" json:"hooks"`
	LanguageFingerprint  string `bson:"language_fingerprint" json:"language_fingerprint"`
	Rhythm               string `bson:"rhythm" json:"rhythm"`
	Punctuation          string `bson:"punctuation" json:"punctuation"`
	ContentPatterns      string `bson:"content_patterns" json:"content_patterns"`
	KnowledgeTranslation string `bson:"knowledge_translation" json:"knowledge_translation"`
	CtaStyle             string `bson:"cta_style" json:"cta_style"`
	Examples             string `bson:"examples" json:"examples"`
	Avoid                string `bson:"avoid" json:"avoid"`
}

type PersonaGuard struct {
	Avoid     []string `bson:"avoid" json:"avoid"`
	MaxChars  int      `bson:"max_chars" json:"max_chars"`
	BanAiTone bool     `bson:"ban_ai_tone" json:"ban_ai_tone"`
}

// ActivePersona stores per-owner active id
type ActivePersona struct {
	OwnerUID  int64  `bson:"_id" json:"owner_uid"`
	PersonaID string `bson:"persona_id" json:"persona_id"`
	UpdatedAt int64  `bson:"updated_at" json:"updated_at"`
}

// Play — PL domain
type ExternalTarget struct {
	URL            string `bson:"url" json:"url"`
	RawURL         string `bson:"raw_url,omitempty" json:"raw_url,omitempty"`
	Shortcode      string `bson:"shortcode,omitempty" json:"shortcode,omitempty"`
	AuthorUsername string `bson:"author_username,omitempty" json:"author_username,omitempty"`
	TextPreview    string `bson:"text_preview,omitempty" json:"text_preview,omitempty"`
	MediaID        string `bson:"media_id,omitempty" json:"media_id,omitempty"`
	ResolvedAt     int64  `bson:"resolved_at,omitempty" json:"resolved_at,omitempty"`
}

type PlayStep struct {
	ID                   string   `bson:"id" json:"id"`
	SortOrder            int      `bson:"sort_order" json:"sort_order"`
	Kind                 string   `bson:"kind" json:"kind"`
	AccountID            string   `bson:"account_id" json:"account_id"`
	Text                 string   `bson:"text" json:"text"`
	DelayFromPreviousSec int      `bson:"delay_from_previous_sec" json:"delay_from_previous_sec"`
	PersonaID            string   `bson:"persona_id,omitempty" json:"persona_id,omitempty"`
	BrandID              string   `bson:"brand_id,omitempty" json:"brand_id,omitempty"`
	ImageURLs            []string `bson:"image_urls,omitempty" json:"image_urls,omitempty"`
}

type Play struct {
	ID              string          `bson:"_id" json:"id"`
	OwnerUID        int64           `bson:"owner_uid" json:"owner_uid"`
	Title           string          `bson:"title" json:"title"`
	Topic           string          `bson:"topic" json:"topic"`
	Status          string          `bson:"status" json:"status"`
	LeadAccountID   string          `bson:"lead_account_id" json:"lead_account_id"`
	CastAccountIDs  []string        `bson:"cast_account_ids" json:"cast_account_ids"`
	TargetOwnPostID string          `bson:"target_own_post_id,omitempty" json:"target_own_post_id,omitempty"`
	TargetExternal  *ExternalTarget `bson:"target_external,omitempty" json:"target_external,omitempty"`
	Steps           []PlayStep      `bson:"steps" json:"steps"`
	ScheduleStartAt int64           `bson:"schedule_start_at" json:"schedule_start_at"`
	IntervalMinutes int             `bson:"interval_minutes,omitempty" json:"interval_minutes,omitempty"`
	CreatedAt       int64           `bson:"created_at" json:"created_at"`
	UpdatedAt       int64           `bson:"updated_at" json:"updated_at"`
}

// Outbox
type OutboxStep struct {
	ID        string `bson:"id" json:"id"`
	StepID    string `bson:"step_id" json:"step_id"`
	SortOrder int    `bson:"sort_order" json:"sort_order"`
	Kind      string `bson:"kind" json:"kind"`
	AccountID string `bson:"account_id" json:"account_id"`
	Text      string `bson:"text" json:"text"`
	// TopicTag — 主貼可用的 Threads 話題標籤
	TopicTag string `bson:"topic_tag,omitempty" json:"topic_tag,omitempty"`
	// ReplyControl — 主貼 who-can-reply（Threads reply_control，發文時寫入）
	ReplyControl string `bson:"reply_control,omitempty" json:"reply_control,omitempty"`
	// ImageURLs — 公開 https 圖網址（Meta image_url 可抓；勿存 data URL）
	ImageURLs   []string `bson:"image_urls,omitempty" json:"image_urls,omitempty"`
	Status      string   `bson:"status" json:"status"`
	Error       string   `bson:"error,omitempty" json:"error,omitempty"`
	ScheduledAt int64    `bson:"scheduled_at,omitempty" json:"scheduled_at,omitempty"`
	PublishedAt int64    `bson:"published_at,omitempty" json:"published_at,omitempty"`
	// MediaID after successful publish (for reply chain)
	MediaID string `bson:"media_id,omitempty" json:"media_id,omitempty"`
	// ReplyTo is parent media id (external or previous root)
	ReplyTo string `bson:"reply_to,omitempty" json:"reply_to,omitempty"`
	// Lease fields are internal worker fencing state. A unique owner is used for
	// every claim so an expired publisher cannot finalize a reclaimed step.
	LeaseOwner     string `bson:"lease_owner,omitempty" json:"-"`
	LeaseExpiresAt int64  `bson:"lease_expires_at,omitempty" json:"-"`
}

type OutboxBundle struct {
	ID       string       `bson:"_id" json:"id"`
	OwnerUID int64        `bson:"owner_uid" json:"owner_uid"`
	PlayID   string       `bson:"play_id" json:"play_id"`
	Title    string       `bson:"title" json:"title"`
	Status   string       `bson:"status" json:"status"`
	Steps    []OutboxStep `bson:"steps" json:"steps"`
	// Root reply target for under-post schemes
	ReplyToMediaID string `bson:"reply_to_media_id,omitempty" json:"reply_to_media_id,omitempty"`
	CreatedAt      int64  `bson:"created_at" json:"created_at"`
	UpdatedAt      int64  `bson:"updated_at" json:"updated_at"`
}

// OwnPost / Mention
type OwnPostReply struct {
	ID            string `bson:"id" json:"id"`
	Username      string `bson:"username" json:"username"`
	Text          string `bson:"text" json:"text"`
	CreatedAt     int64  `bson:"created_at" json:"created_at"`
	LikeCount     int    `bson:"like_count,omitempty" json:"like_count,omitempty"`
	ReplyStatus   string `bson:"reply_status,omitempty" json:"reply_status,omitempty"`
	RepliedBy     string `bson:"replied_by,omitempty" json:"replied_by,omitempty"`
	RepliedAt     int64  `bson:"replied_at,omitempty" json:"replied_at,omitempty"`
	ParentReplyID string `bson:"parent_reply_id,omitempty" json:"parent_reply_id,omitempty"`
	IsMine        bool   `bson:"is_mine,omitempty" json:"is_mine,omitempty"`
	// Threads hide_status：NOT_HUSHED / HIDDEN / BLOCKED / …
	HideStatus string `bson:"hide_status,omitempty" json:"hide_status,omitempty"`
}

type OwnPost struct {
	ID             string         `bson:"_id" json:"id"`
	OwnerUID       int64          `bson:"owner_uid" json:"owner_uid"`
	AccountID      string         `bson:"account_id" json:"account_id"`
	MediaID        string         `bson:"media_id,omitempty" json:"media_id,omitempty"`
	Text           string         `bson:"text" json:"text"`
	MediaType      string         `bson:"media_type" json:"media_type"`
	MediaURL       string         `bson:"media_url,omitempty" json:"media_url,omitempty"`
	ThumbnailURL   string         `bson:"thumbnail_url,omitempty" json:"thumbnail_url,omitempty"`
	Permalink      string         `bson:"permalink,omitempty" json:"permalink,omitempty"`
	Shortcode      string         `bson:"shortcode,omitempty" json:"shortcode,omitempty"`
	TopicTag       string         `bson:"topic_tag,omitempty" json:"topic_tag,omitempty"`
	LikeCount      int            `bson:"like_count" json:"like_count"`
	ReplyCount     int            `bson:"reply_count" json:"reply_count"`
	RepostCount    int            `bson:"repost_count" json:"repost_count"`
	QuoteCount     int            `bson:"quote_count" json:"quote_count"`
	ViewCount      int            `bson:"view_count" json:"view_count"`
	ShareCount     int            `bson:"share_count" json:"share_count"`
	InsightsStatus string         `bson:"insights_status,omitempty" json:"insights_status,omitempty"`
	FormulaSummary string         `bson:"formula_summary,omitempty" json:"formula_summary,omitempty"`
	Insight        string         `bson:"insight,omitempty" json:"insight,omitempty"`
	FormulaDetail  string         `bson:"formula_detail,omitempty" json:"formula_detail,omitempty"`
	Replies        []OwnPostReply `bson:"replies" json:"replies"`
	PublishedAt    int64          `bson:"published_at" json:"published_at"`
	// everyone | accounts_you_follow | mentioned_only | parent_post_author_only | followers_only
	ReplyControl string `bson:"reply_control,omitempty" json:"reply_control,omitempty"`
}

type Mention struct {
	ID             string `bson:"_id" json:"id"`
	OwnerUID       int64  `bson:"owner_uid" json:"owner_uid"`
	AccountID      string `bson:"account_id" json:"account_id"`
	MediaID        string `bson:"media_id,omitempty" json:"media_id,omitempty"` // Threads media id（回覆 reply_to）
	FromUsername   string `bson:"from_username" json:"from_username"`
	Text           string `bson:"text" json:"text"`
	ContextSnippet string `bson:"context_snippet" json:"context_snippet"`
	Permalink      string `bson:"permalink,omitempty" json:"permalink,omitempty"`
	RootPostID     string `bson:"root_post_id,omitempty" json:"root_post_id,omitempty"`
	ParentID       string `bson:"parent_id,omitempty" json:"parent_id,omitempty"`
	Status         string `bson:"status" json:"status"`
	DraftText      string `bson:"draft_text,omitempty" json:"draft_text,omitempty"`
	CreatedAt      int64  `bson:"created_at" json:"created_at"`
}

type SyncMeta struct {
	OwnerUID     int64 `bson:"_id" json:"owner_uid"`
	LastSyncedAt int64 `bson:"last_synced_at" json:"last_synced_at"`
}

type ViralAnalysis struct {
	Hooks     string `json:"hooks"`
	Structure string `json:"structure"`
	Emotion   string `json:"emotion"`
	Summary   string `json:"summary"`
	CTA       string `json:"cta,omitempty"`
	Copyable  string `json:"copyable,omitempty"` // 可複製要點
	Risks     string `json:"risks,omitempty"`    // 風險／禁忌
}

// PersonaPreview — 試產主貼 + 回文（真 LLM + 可選新聞話題）
type PersonaPreview struct {
	Topic       string `json:"topic"`
	TopicSource string `json:"topic_source"` // news | manual | fallback
	PostText    string `json:"post_text"`
	ReplyText   string `json:"reply_text"`
	Notes       string `json:"notes,omitempty"`
}

// PublishRequest for transport (must be called for real publish).
type PublishRequest struct {
	AccessToken string
	AccountID   string
	Text        string
	ReplyTo     string // empty = root post
	// TopicTag — Threads 話題標籤（API topic_tag；1～50 字，不可含 . &）
	TopicTag string
	// ReplyControl — 主貼 who-can-reply（發文時帶入 container）
	ReplyControl string
	// ImageURLs — 公開可抓的 http(s) 圖；空＝純文字 TEXT
	ImageURLs []string
}

type PublishResult struct {
	MediaID string
}
