package domain

import (
	"math"
	"time"
)

type TaskOrigin string

const (
	OriginImported   TaskOrigin = "imported"
	OriginSubdivided TaskOrigin = "subdivided"
	OriginExtended   TaskOrigin = "extended"
)

type External struct {
	System      string         `bson:"system" json:"system"`
	Key         string         `bson:"key" json:"key"`
	URL         string         `bson:"url" json:"url"`
	Type        string         `bson:"type" json:"type"` // epic | story | task (icon only)
	Raw         map[string]any `bson:"raw" json:"-"`
	Orphaned    bool           `bson:"orphaned" json:"orphaned"`
	ContentHash string         `bson:"contentHash" json:"-"` // change detection for upstream edits
}

type TaskAttachment struct {
	Name     string `bson:"name" json:"name"`
	URL      string `bson:"url" json:"url"`
	MimeType string `bson:"mimeType" json:"mimeType"`
	FileID   string `bson:"fileId,omitempty" json:"fileId,omitempty"`
}

type Assignee struct {
	Kind   string `bson:"kind" json:"kind"` // human | ai
	UserID string `bson:"userId,omitempty" json:"userId,omitempty"`
	JobID  string `bson:"jobId,omitempty" json:"jobId,omitempty"`
}

type ClaimRequest struct {
	DeveloperID string    `bson:"developerId" json:"developerId"`
	Note        string    `bson:"note" json:"note"`
	At          time.Time `bson:"at" json:"at"`
}

type TimelineEntry struct {
	At      time.Time      `bson:"at" json:"at"`
	ActorID string         `bson:"actorId" json:"actorId"` // user id or "system"
	Event   string         `bson:"event" json:"event"`
	Data    map[string]any `bson:"data,omitempty" json:"data,omitempty"`
}

type Comment struct {
	ID       string    `bson:"_id" json:"id"`
	AuthorID string    `bson:"authorId" json:"authorId"`
	Body     string    `bson:"body" json:"body"` // sanitized HTML
	At       time.Time `bson:"at" json:"at"`
}

type TimeLogEntry struct {
	DeveloperID string    `bson:"developerId" json:"developerId"`
	Minutes     int       `bson:"minutes" json:"minutes"`
	Note        string    `bson:"note" json:"note"`
	At          time.Time `bson:"at" json:"at"`
}

// Task is the central work item (§4.4).
type Task struct {
	ID                 string           `bson:"_id" json:"id"`
	CustomerID         string           `bson:"customerId" json:"customerId"`
	ConsultantID       string           `bson:"consultantId" json:"consultantId"`
	Origin             TaskOrigin       `bson:"origin" json:"origin"`
	ParentID           string           `bson:"parentId,omitempty" json:"parentId,omitempty"`
	RootID             string           `bson:"rootId" json:"rootId"`
	External           *External        `bson:"external,omitempty" json:"external,omitempty"`
	Title              string           `bson:"title" json:"title"`
	Description        string           `bson:"description" json:"description"`
	AcceptanceCriteria []string         `bson:"acceptanceCriteria" json:"acceptanceCriteria"`
	Attachments        []TaskAttachment `bson:"attachments" json:"attachments"`
	Links              []string         `bson:"links" json:"links"`
	EffortCoefficient  float64          `bson:"effortCoefficient" json:"effortCoefficient"`
	Budget             float64          `bson:"budget" json:"budget"`
	Bounty             float64          `bson:"bounty" json:"bounty"`
	Status             TaskStatus       `bson:"status" json:"status"`
	Assignee           *Assignee        `bson:"assignee,omitempty" json:"assignee,omitempty"`
	ClaimRequests      []ClaimRequest   `bson:"claimRequests" json:"claimRequests"`
	AtomizationNote    string           `bson:"atomizationNote,omitempty" json:"atomizationNote,omitempty"`
	Timeline           []TimelineEntry  `bson:"timeline" json:"timeline"`
	Comments           []Comment        `bson:"comments" json:"comments"`
	TimeLog            []TimeLogEntry   `bson:"timeLog" json:"timeLog"`
	PublishedAt        time.Time        `bson:"publishedAt,omitempty" json:"publishedAt,omitempty"` // stale-task aging (§11.19)
	CreatedAt          time.Time        `bson:"createdAt" json:"createdAt"`
	UpdatedAt          time.Time        `bson:"updatedAt" json:"updatedAt"`
	Version            int64            `bson:"version" json:"version"`
}

// ComputeBounty implements §6.1: round(coefficient × budget, 2).
func ComputeBounty(coefficient, budget float64) float64 {
	return math.Round(coefficient*budget*100) / 100
}

// IsAssignedTo reports whether the human developer holds the task.
func (t *Task) IsAssignedTo(userID string) bool {
	return t.Assignee != nil && t.Assignee.Kind == "human" && t.Assignee.UserID == userID
}

// HasClaimFrom reports an open claim request by the developer.
func (t *Task) HasClaimFrom(developerID string) bool {
	for _, cr := range t.ClaimRequests {
		if cr.DeveloperID == developerID {
			return true
		}
	}
	return false
}
