package domain

import (
	"context"
	"errors"
	"time"

	"github.com/google/uuid"
)

var (
	ErrNotFound      = errors.New("growth not found")
	ErrForbidden     = errors.New("growth access denied")
	ErrValidation    = errors.New("growth validation")
	ErrThrottle      = errors.New("account health throttle")
	ErrReviewPending = errors.New("draft review required")
	ErrRateLimited   = errors.New("checkup regenerate limit")
)

const (
	SourceScoutOutreach = "scout_outreach"
	SourceOutboxStep    = "outbox_step"

	KindReach       = "reach"
	KindReply       = "reply"
	KindFollow      = "follow"
	KindConversion  = "conversion"
	KindInteraction = "interaction"

	ConfidenceConfirmed = "confirmed"
	ConfidencePossible  = "possible"

	StatusObserving = "observing"
	StatusConfirmed = "confirmed"
	StatusPossible  = "possible"
	StatusExpired   = "expired"
	StatusAmended   = "amended"

	CheckupGenerating = "generating"
	CheckupReady      = "ready"
	CheckupFailed     = "failed"

	HealthNormal    = "normal"
	HealthWarn      = "warn"
	HealthThrottle  = "throttle"

	ReviewNone     = "none"
	ReviewPending  = "pending"
	ReviewApproved = "approved"
	ReviewRejected = "rejected"

	RewardCredited = "credited"
	RewardCapped   = "capped"
	RewardSkipped  = "skipped"

	ObserveWindow = 72 * time.Hour
)

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

func NewID() string { return uuid.NewString() }

type OutcomeEvent struct {
	ID                   string  `bson:"_id" json:"id"`
	OwnerUID             int64   `bson:"owner_uid" json:"owner_uid"`
	SourceType           string  `bson:"source_type" json:"source_type"`
	SourceID             string  `bson:"source_id" json:"source_id"`
	ThreadsAccountID     string  `bson:"threads_account_id,omitempty" json:"threads_account_id,omitempty"`
	Kind                 string  `bson:"kind" json:"kind"`
	Confidence           string  `bson:"confidence" json:"confidence"`
	Status               string  `bson:"status" json:"status"`
	ReplyCountDelta      int     `bson:"reply_count_delta,omitempty" json:"reply_count_delta,omitempty"`
	LikeCountDelta       int     `bson:"like_count_delta,omitempty" json:"like_count_delta,omitempty"`
	FollowersDelta       int     `bson:"followers_delta,omitempty" json:"followers_delta,omitempty"`
	ConversionAmount     float64 `bson:"conversion_amount,omitempty" json:"conversion_amount,omitempty"`
	ConversionNote       string  `bson:"conversion_note,omitempty" json:"conversion_note,omitempty"`
	ConversionCurrency   string  `bson:"conversion_currency,omitempty" json:"conversion_currency,omitempty"`
	HasConversion        bool    `bson:"has_conversion" json:"has_conversion"`
	ClickCount           int     `bson:"click_count,omitempty" json:"click_count,omitempty"`
	WindowEndsAt         int64   `bson:"window_ends_at" json:"window_ends_at"`
	SentAt               int64   `bson:"sent_at" json:"sent_at"`
	CreatedAt            int64   `bson:"created_at" json:"created_at"`
	UpdatedAt            int64   `bson:"updated_at" json:"updated_at"`
}

const (
	KindClick = "click"

	PlaybookBrief   = "brief"
	PlaybookPersona = "persona"
	PlaybookPlay    = "play"

	WSRoleOwner    = "owner"
	WSRoleEditor   = "editor"
	WSRoleReviewer = "reviewer"
)

type Playbook struct {
	ID          string `bson:"_id" json:"id"`
	OwnerUID    int64  `bson:"owner_uid" json:"owner_uid"`
	Kind        string `bson:"kind" json:"kind"`
	Title       string `bson:"title" json:"title"`
	Niche       string `bson:"niche" json:"niche"`
	Body        string `bson:"body" json:"body"`
	Anonymous   bool   `bson:"anonymous" json:"anonymous"`
	ImportCount int    `bson:"import_count" json:"import_count"`
	CreatedAt   int64  `bson:"created_at" json:"created_at"`
	UpdatedAt   int64  `bson:"updated_at" json:"updated_at"`
}

type UtmLink struct {
	ID             string `bson:"_id" json:"id"`
	Code           string `bson:"code" json:"code"`
	OwnerUID       int64  `bson:"owner_uid" json:"owner_uid"`
	DestinationURL string `bson:"destination_url" json:"destination_url"`
	OutcomeID      string `bson:"outcome_id,omitempty" json:"outcome_id,omitempty"`
	Label          string `bson:"label,omitempty" json:"label,omitempty"`
	Clicks         int    `bson:"clicks" json:"clicks"`
	CreatedAt      int64  `bson:"created_at" json:"created_at"`
}

type WorkspaceMember struct {
	ID          string `bson:"_id" json:"id"`
	WorkspaceID string `bson:"workspace_id" json:"workspace_id"`
	UID         int64  `bson:"uid" json:"uid"`
	Role        string `bson:"role" json:"role"`
	JoinedAt    int64  `bson:"joined_at" json:"joined_at"`
}

// BenchmarkSample — anonymized contribution for niche medians
type BenchmarkSample struct {
	ID        string  `bson:"_id" json:"id"`
	Niche     string  `bson:"niche" json:"niche"`
	EngRate   float64 `bson:"eng_rate" json:"eng_rate"`
	AvgViews  float64 `bson:"avg_views" json:"avg_views"`
	OwnerHash string  `bson:"owner_hash" json:"owner_hash"` // one sample per owner per niche
	UpdatedAt int64   `bson:"updated_at" json:"updated_at"`
}

type OutcomeSummary struct {
	From             int64
	To               int64
	Reach            int
	Conversations    int
	FollowsPossible  int
	FollowsConfirmed int
	Conversions      int
	ConversionAmount float64
}

type CheckupFinding struct {
	Claim    string   `bson:"claim" json:"claim"`
	Evidence []string `bson:"evidence" json:"evidence"`
}

type CheckupAction struct {
	Title    string `bson:"title" json:"title"`
	Reason   string `bson:"reason" json:"reason"`
	Deeplink string `bson:"deeplink" json:"deeplink"`
}

type WeeklyCheckup struct {
	ID        string           `bson:"_id" json:"id"`
	OwnerUID  int64            `bson:"owner_uid" json:"owner_uid"`
	WeekKey   string           `bson:"week_key" json:"week_key"`
	Status    string           `bson:"status" json:"status"`
	Summary   string           `bson:"summary" json:"summary"`
	Findings  []CheckupFinding `bson:"findings" json:"findings"`
	Actions   []CheckupAction  `bson:"actions" json:"actions"`
	Error     string           `bson:"error,omitempty" json:"error,omitempty"`
	CreatedAt int64            `bson:"created_at" json:"created_at"`
	UpdatedAt int64            `bson:"updated_at" json:"updated_at"`
}

type AccountHealth struct {
	ThreadsAccountID string   `bson:"_id" json:"threads_account_id"`
	OwnerUID         int64    `bson:"owner_uid" json:"owner_uid"`
	Score            int      `bson:"score" json:"score"`
	Level            string   `bson:"level" json:"level"`
	Factors          []string `bson:"factors" json:"factors"`
	Advice           string   `bson:"advice" json:"advice"`
	ComputedAt       int64    `bson:"computed_at" json:"computed_at"`
}

type Workspace struct {
	ID             string `bson:"_id" json:"id"`
	OwnerUID       int64  `bson:"owner_uid" json:"owner_uid"`
	Name           string `bson:"name" json:"name"`
	ReviewRequired bool   `bson:"review_required" json:"review_required"`
	IsDefault      bool   `bson:"is_default" json:"is_default"`
	Archived       bool   `bson:"archived" json:"archived"`
	FooterText     string `bson:"footer_text,omitempty" json:"footer_text,omitempty"`
	HidePoweredBy  bool   `bson:"hide_powered_by,omitempty" json:"hide_powered_by,omitempty"`
	BrandName      string `bson:"brand_name,omitempty" json:"brand_name,omitempty"`
	CreatedAt      int64  `bson:"created_at" json:"created_at"`
	UpdatedAt      int64  `bson:"updated_at" json:"updated_at"`
}

type MemberWorkspaceState struct {
	OwnerUID           int64  `bson:"_id" json:"owner_uid"`
	CurrentWorkspaceID string `bson:"current_workspace_id" json:"current_workspace_id"`
	UpdatedAt          int64  `bson:"updated_at" json:"updated_at"`
}

type DraftReview struct {
	ID          string `bson:"_id" json:"id"`
	OwnerUID    int64  `bson:"owner_uid" json:"owner_uid"`
	WorkspaceID string `bson:"workspace_id" json:"workspace_id"`
	RefType     string `bson:"ref_type" json:"ref_type"`
	RefID       string `bson:"ref_id" json:"ref_id"`
	Status      string `bson:"status" json:"status"`
	Reason      string `bson:"reason,omitempty" json:"reason,omitempty"`
	CreatedAt   int64  `bson:"created_at" json:"created_at"`
	UpdatedAt   int64  `bson:"updated_at" json:"updated_at"`
}

type InviteReward struct {
	ID         string `bson:"_id" json:"id"`
	InviterUID int64  `bson:"inviter_uid" json:"inviter_uid"`
	InviteeUID int64  `bson:"invitee_uid" json:"invitee_uid"`
	PlanID     string `bson:"plan_id" json:"plan_id"`
	Points     int    `bson:"points" json:"points"`
	Status     string `bson:"status" json:"status"`
	CreatedAt  int64  `bson:"created_at" json:"created_at"`
}

type OutcomeListFilter struct {
	Kind       string
	Confidence string
	SourceType string
	From       int64
	To         int64
	Page       int
	PageSize   int
}

type Repository interface {
	// Outcomes
	UpsertOutcomeBySource(ctx context.Context, e *OutcomeEvent) error
	GetOutcome(ctx context.Context, id string) (*OutcomeEvent, error)
	ListOutcomes(ctx context.Context, ownerUID int64, f OutcomeListFilter) ([]*OutcomeEvent, int64, error)
	SaveOutcome(ctx context.Context, e *OutcomeEvent) error
	ListObservingDue(ctx context.Context, now int64, limit int) ([]*OutcomeEvent, error)

	// Checkups
	SaveCheckup(ctx context.Context, c *WeeklyCheckup) error
	GetCheckup(ctx context.Context, id string) (*WeeklyCheckup, error)
	LatestCheckup(ctx context.Context, ownerUID int64) (*WeeklyCheckup, error)
	ListCheckups(ctx context.Context, ownerUID int64, page, pageSize int) ([]*WeeklyCheckup, int64, error)
	CountCheckupGenerations(ctx context.Context, ownerUID int64, sinceNano int64) (int64, error)

	// Health
	SaveHealth(ctx context.Context, h *AccountHealth) error
	GetHealth(ctx context.Context, accountID string) (*AccountHealth, error)
	ListHealth(ctx context.Context, ownerUID int64) ([]*AccountHealth, error)

	// Workspace
	SaveWorkspace(ctx context.Context, w *Workspace) error
	GetWorkspace(ctx context.Context, id string) (*Workspace, error)
	ListWorkspaces(ctx context.Context, ownerUID int64, includeArchived bool) ([]*Workspace, error)
	CountActiveWorkspaces(ctx context.Context, ownerUID int64) (int64, error)
	GetMemberWSState(ctx context.Context, ownerUID int64) (*MemberWorkspaceState, error)
	SaveMemberWSState(ctx context.Context, s *MemberWorkspaceState) error

	// Reviews
	SaveReview(ctx context.Context, r *DraftReview) error
	GetReview(ctx context.Context, id string) (*DraftReview, error)
	FindReviewByRef(ctx context.Context, ownerUID int64, refType, refID string) (*DraftReview, error)
	ListReviews(ctx context.Context, ownerUID int64, status string, page, pageSize int) ([]*DraftReview, int64, error)

	// Invite rewards
	SaveInviteReward(ctx context.Context, r *InviteReward) error
	ListInviteRewards(ctx context.Context, inviterUID int64, limit int) ([]*InviteReward, error)
	SumInviteRewardPointsMonth(ctx context.Context, inviterUID int64, monthStartNano int64) (int, error)
	SumInviteRewardPointsTotal(ctx context.Context, inviterUID int64) (int, error)
	HasInviteRewardForInvitee(ctx context.Context, inviteeUID int64) (bool, error)

	// P2 Playbooks
	SavePlaybook(ctx context.Context, p *Playbook) error
	GetPlaybook(ctx context.Context, id string) (*Playbook, error)
	ListPlaybooks(ctx context.Context, kind, niche string, ownerOnlyUID int64, page, pageSize int) ([]*Playbook, int64, error)
	DeletePlaybook(ctx context.Context, id string) error
	IncPlaybookImport(ctx context.Context, id string) error

	// P2 UTM
	SaveUtmLink(ctx context.Context, u *UtmLink) error
	GetUtmByCode(ctx context.Context, code string) (*UtmLink, error)
	ListUtmLinks(ctx context.Context, ownerUID int64) ([]*UtmLink, error)
	IncUtmClick(ctx context.Context, code string) (*UtmLink, error)

	// P2 Workspace members
	SaveWorkspaceMember(ctx context.Context, m *WorkspaceMember) error
	ListWorkspaceMembers(ctx context.Context, workspaceID string) ([]*WorkspaceMember, error)
	RemoveWorkspaceMember(ctx context.Context, workspaceID string, uid int64) error
	IsWorkspaceMember(ctx context.Context, workspaceID string, uid int64) (bool, string, error)

	// P2 Benchmark
	UpsertBenchmarkSample(ctx context.Context, s *BenchmarkSample) error
	ListBenchmarkSamples(ctx context.Context, niche string, limit int) ([]*BenchmarkSample, error)
}
