package domain

import (
	"fmt"
	"strings"
	"time"

	"github.com/google/uuid"
)

func NowNano() int64 { return time.Now().UTC().UnixNano() }
func NewID() string  { return uuid.NewString() }

const (
	StageNewFound = "new_found"
	StageEngaged  = "engaged"
	StageDMSent   = "dm_sent"
	StageReplied  = "replied"
	StageQuoted   = "quoted"
	StageWon      = "won"
	StageLost     = "lost"

	PlatformThreads = "threads"

	TouchStage      = "stage"
	TouchReply      = "reply"
	TouchNote       = "note"
	TouchConversion = "conversion"

	FollowUpScheduled = "scheduled"
	FollowUpNotified  = "notified"
	FollowUpDone      = "done"
	FollowUpSnoozed   = "snoozed"
	FollowUpEscalated = "escalated"

	DefaultFollowUpDays = 3
	// MaxFollowUpNotifications：通知達此次數仍無動作即 escalated（spec FU-03）。
	MaxFollowUpNotifications = 2
)

type Contact struct {
	ID             string   `bson:"_id" json:"id"`
	OwnerUID       int64    `bson:"owner_uid" json:"owner_uid"`
	SourcePlatform string   `bson:"source_platform" json:"source_platform"`
	AuthorHandle   string   `bson:"author_handle" json:"author_handle"`
	DisplayName    string   `bson:"display_name,omitempty" json:"display_name,omitempty"`
	Stage          string   `bson:"stage" json:"stage"`
	NeedsFollowUp  bool     `bson:"needs_follow_up" json:"needs_follow_up"`
	FollowUpDays   int      `bson:"follow_up_days" json:"follow_up_days"`
	LastTouchAt    int64    `bson:"last_touch_at,omitempty" json:"last_touch_at,omitempty"`
	OpportunityIDs []string `bson:"opportunity_ids" json:"opportunity_ids"`
	MergedFrom     []string `bson:"merged_from,omitempty" json:"merged_from,omitempty"`
	TopIntentBand  string   `bson:"top_intent_band,omitempty" json:"top_intent_band,omitempty"`
	TopIntentScore int      `bson:"top_intent_score,omitempty" json:"top_intent_score,omitempty"`
	// OutcomeID links the latest conversion in growth_outcomes.
	OutcomeID string `bson:"outcome_id,omitempty" json:"outcome_id,omitempty"`
	// RemovedAt hides the contact from the working list without breaking
	// opportunity, touch, or conversion history that still references its ID.
	RemovedAt int64 `bson:"removed_at,omitempty" json:"removed_at,omitempty"`
	CreatedAt int64 `bson:"created_at" json:"created_at"`
	UpdatedAt int64 `bson:"updated_at" json:"updated_at"`
}

type ContactTouch struct {
	ID        string `bson:"_id" json:"id"`
	OwnerUID  int64  `bson:"owner_uid" json:"owner_uid"`
	ContactID string `bson:"contact_id" json:"contact_id"`
	Type      string `bson:"type" json:"type"`
	FromStage string `bson:"from_stage,omitempty" json:"from_stage,omitempty"`
	ToStage   string `bson:"to_stage,omitempty" json:"to_stage,omitempty"`
	Body      string `bson:"body,omitempty" json:"body,omitempty"`
	ActorUID  int64  `bson:"actor_uid" json:"actor_uid"`
	CreatedAt int64  `bson:"created_at" json:"created_at"`
}

type FollowUp struct {
	ID            string `bson:"_id" json:"id"`
	OwnerUID      int64  `bson:"owner_uid" json:"owner_uid"`
	ContactID     string `bson:"contact_id" json:"contact_id"`
	DueAt         int64  `bson:"due_at" json:"due_at"`
	Status        string `bson:"status" json:"status"`
	NotifiedCount int    `bson:"notified_count" json:"notified_count"`
	CreatedAt     int64  `bson:"created_at" json:"created_at"`
	UpdatedAt     int64  `bson:"updated_at" json:"updated_at"`
}

type ContactListFilter struct {
	Query    string
	Stage    string
	FollowUp *bool
	Band     string
	Sort     string // last_touch_at | intent_score
	Page     int
	PageSize int
}

type FollowUpListFilter struct {
	Status   string
	Page     int
	PageSize int
}

func IsStage(s string) bool {
	switch s {
	case StageNewFound, StageEngaged, StageDMSent, StageReplied, StageQuoted, StageWon, StageLost:
		return true
	}
	return false
}

func (c *Contact) Normalize() error {
	if c.OwnerUID <= 0 {
		return fmt.Errorf("%w: owner_uid required", ErrValidation)
	}
	c.AuthorHandle = strings.TrimPrefix(strings.TrimSpace(c.AuthorHandle), "@")
	if c.AuthorHandle == "" {
		return fmt.Errorf("%w: author_handle required", ErrValidation)
	}
	if c.SourcePlatform == "" {
		c.SourcePlatform = PlatformThreads
	}
	if c.Stage == "" {
		c.Stage = StageNewFound
	}
	if !IsStage(c.Stage) {
		return fmt.Errorf("%w: unknown stage %q", ErrValidation, c.Stage)
	}
	if c.FollowUpDays <= 0 {
		c.FollowUpDays = DefaultFollowUpDays
	}
	if c.OpportunityIDs == nil {
		c.OpportunityIDs = []string{}
	}
	return nil
}
