package chat

import (
	"time"

	"github.com/google/uuid"
)

// ===== Request DTOs =====

// CreateConversationReq is the HTTP request body for POST /conversations.
type CreateConversationReq struct {
	ModelID       uuid.UUID  `json:"model_id"`
	TemplateID    *uuid.UUID `json:"template_id,omitempty"`
	SystemPrompt  *string    `json:"system_prompt,omitempty"`
	ProjectID     *uuid.UUID `json:"project_id,omitempty"`
	WorkspaceID   *uuid.UUID `json:"workspace_id,omitempty"`
	IssueID       *uuid.UUID `json:"issue_id,omitempty"`
	RequirementID *uuid.UUID `json:"requirement_id,omitempty"`
}

// UpdateConversationTitleReq is the HTTP request body for PATCH /conversations/{id}.
type UpdateConversationTitleReq struct {
	Title string `json:"title"`
}

// SendMessageReq is the HTTP request body for POST /conversations/{id}/messages.
type SendMessageReq struct {
	Content       string      `json:"content"`
	AttachmentIDs []uuid.UUID `json:"attachment_ids,omitempty"`
}

// CreateTemplateReq is the HTTP request body for POST /prompt-templates.
type CreateTemplateReq struct {
	Name    string `json:"name"`
	Content string `json:"content"`
	Scope   string `json:"scope"` // "user" | "system"
}

// UpdateTemplateReq is the HTTP request body for PATCH /prompt-templates/{id}.
type UpdateTemplateReq struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

// CreateEndpointReq is the HTTP request body for POST /admin/llm-endpoints.
type CreateEndpointReq struct {
	Provider    string `json:"provider"`
	DisplayName string `json:"display_name"`
	BaseURL     string `json:"base_url"`
	APIKey      string `json:"api_key"`
}

// UpdateEndpointReq is the HTTP request body for PATCH /admin/llm-endpoints/{id}.
type UpdateEndpointReq struct {
	DisplayName *string `json:"display_name,omitempty"`
	BaseURL     *string `json:"base_url,omitempty"`
	APIKey      *string `json:"api_key,omitempty"`
}

// CreateModelReq is the HTTP request body for POST /admin/llm-models.
type CreateModelReq struct {
	EndpointID                   uuid.UUID         `json:"endpoint_id"`
	ModelID                      string            `json:"model_id"`
	DisplayName                  string            `json:"display_name"`
	Capabilities                 ModelCapabilities `json:"capabilities"`
	ContextWindow                int               `json:"context_window"`
	MaxOutputTokens              int               `json:"max_output_tokens"`
	PromptPricePerMillionUSD     float64           `json:"prompt_price_per_million_usd"`
	CompletionPricePerMillionUSD float64           `json:"completion_price_per_million_usd"`
	ThinkingPricePerMillionUSD   float64           `json:"thinking_price_per_million_usd"`
	IsTitleGenerator             bool              `json:"is_title_generator"`
	Enabled                      bool              `json:"enabled"`
	SortOrder                    int               `json:"sort_order"`
}

// UpdateModelReq is the HTTP request body for PATCH /admin/llm-models/{id}.
type UpdateModelReq struct {
	DisplayName                  *string            `json:"display_name,omitempty"`
	Capabilities                 *ModelCapabilities `json:"capabilities,omitempty"`
	ContextWindow                *int               `json:"context_window,omitempty"`
	MaxOutputTokens              *int               `json:"max_output_tokens,omitempty"`
	PromptPricePerMillionUSD     *float64           `json:"prompt_price_per_million_usd,omitempty"`
	CompletionPricePerMillionUSD *float64           `json:"completion_price_per_million_usd,omitempty"`
	ThinkingPricePerMillionUSD   *float64           `json:"thinking_price_per_million_usd,omitempty"`
	IsTitleGenerator             *bool              `json:"is_title_generator,omitempty"`
	Enabled                      *bool              `json:"enabled,omitempty"`
	SortOrder                    *int               `json:"sort_order,omitempty"`
}

// ===== Response DTOs =====

// ConversationDTO is the JSON representation of a Conversation.
type ConversationDTO struct {
	ID            uuid.UUID  `json:"id"`
	UserID        uuid.UUID  `json:"user_id"`
	ModelID       uuid.UUID  `json:"model_id"`
	SystemPrompt  string     `json:"system_prompt"`
	Title         *string    `json:"title,omitempty"`
	ProjectID     *uuid.UUID `json:"project_id,omitempty"`
	WorkspaceID   *uuid.UUID `json:"workspace_id,omitempty"`
	IssueID       *uuid.UUID `json:"issue_id,omitempty"`
	RequirementID *uuid.UUID `json:"requirement_id,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at"`
}

// MessageDTO is the JSON representation of a Message.
type MessageDTO struct {
	ID               int64           `json:"id"`
	ConversationID   uuid.UUID       `json:"conversation_id"`
	Role             string          `json:"role"`
	Content          string          `json:"content"`
	Thinking         *string         `json:"thinking,omitempty"`
	Status           string          `json:"status"`
	ErrorMessage     *string         `json:"error_message,omitempty"`
	PromptTokens     *int            `json:"prompt_tokens,omitempty"`
	CompletionTokens *int            `json:"completion_tokens,omitempty"`
	ThinkingTokens   *int            `json:"thinking_tokens,omitempty"`
	Attachments      []AttachmentDTO `json:"attachments"`
	CreatedAt        time.Time       `json:"created_at"`
	UpdatedAt        time.Time       `json:"updated_at"`
}

// AttachmentDTO is the JSON representation of an Attachment.
type AttachmentDTO struct {
	ID        uuid.UUID `json:"id"`
	Filename  string    `json:"filename"`
	MimeType  string    `json:"mime_type"`
	SizeBytes int64     `json:"size_bytes"`
	SHA256    string    `json:"sha256"`
	CreatedAt time.Time `json:"created_at"`
}

// SendMessageResp is the response body for POST /conversations/{id}/messages.
type SendMessageResp struct {
	UserMessageID      int64  `json:"user_message_id"`
	AssistantMessageID int64  `json:"assistant_message_id"`
	StreamURL          string `json:"stream_url"`
}

// TemplateDTO is the JSON representation of a PromptTemplate.
type TemplateDTO struct {
	ID        uuid.UUID  `json:"id"`
	Name      string     `json:"name"`
	Content   string     `json:"content"`
	Scope     string     `json:"scope"`
	OwnerID   *uuid.UUID `json:"owner_id,omitempty"`
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
}

// EndpointDTO is the JSON representation of a LLMEndpoint.
// APIKeyEncrypted is intentionally excluded to prevent leaking secrets.
type EndpointDTO struct {
	ID          uuid.UUID `json:"id"`
	Provider    string    `json:"provider"`
	DisplayName string    `json:"display_name"`
	BaseURL     string    `json:"base_url"`
	CreatedBy   uuid.UUID `json:"created_by"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

// ModelDTO is the JSON representation of a LLMModel.
type ModelDTO struct {
	ID                           uuid.UUID         `json:"id"`
	EndpointID                   uuid.UUID         `json:"endpoint_id"`
	ModelID                      string            `json:"model_id"`
	DisplayName                  string            `json:"display_name"`
	Capabilities                 ModelCapabilities `json:"capabilities"`
	ContextWindow                int               `json:"context_window"`
	MaxOutputTokens              int               `json:"max_output_tokens"`
	PromptPricePerMillionUSD     float64           `json:"prompt_price_per_million_usd"`
	CompletionPricePerMillionUSD float64           `json:"completion_price_per_million_usd"`
	ThinkingPricePerMillionUSD   float64           `json:"thinking_price_per_million_usd"`
	IsTitleGenerator             bool              `json:"is_title_generator"`
	Enabled                      bool              `json:"enabled"`
	SortOrder                    int               `json:"sort_order"`
	CreatedAt                    time.Time         `json:"created_at"`
	UpdatedAt                    time.Time         `json:"updated_at"`
}

// DayUsageDTO is the per-day usage row returned to both regular users and admins.
type DayUsageDTO struct {
	Day              time.Time `json:"day"`
	PromptTokens     int       `json:"prompt_tokens"`
	CompletionTokens int       `json:"completion_tokens"`
	ThinkingTokens   int       `json:"thinking_tokens"`
	CostUSD          float64   `json:"cost_usd"`
}

// UserUsageDTO is the per-user aggregate usage row returned to admins.
type UserUsageDTO struct {
	UserID           uuid.UUID `json:"user_id"`
	PromptTokens     int       `json:"prompt_tokens"`
	CompletionTokens int       `json:"completion_tokens"`
	ThinkingTokens   int       `json:"thinking_tokens"`
	CostUSD          float64   `json:"cost_usd"`
}

// ModelUsageDTO is the per-model aggregate usage row returned to admins.
type ModelUsageDTO struct {
	ModelID          uuid.UUID `json:"model_id"`
	PromptTokens     int       `json:"prompt_tokens"`
	CompletionTokens int       `json:"completion_tokens"`
	ThinkingTokens   int       `json:"thinking_tokens"`
	CostUSD          float64   `json:"cost_usd"`
}

// AdminUsageItem is a single aggregated usage row keyed by user/model/day.
type AdminUsageItem struct {
	Key              string  `json:"key"`
	PromptTokens     int     `json:"prompt_tokens"`
	CompletionTokens int     `json:"completion_tokens"`
	ThinkingTokens   int     `json:"thinking_tokens"`
	CostUSD          float64 `json:"cost_usd"`
}

// AdminUsageResp is the response body for GET /admin/usage.
type AdminUsageResp struct {
	Items []AdminUsageItem `json:"items"`
}

// ===== Conversion helpers =====

func toConversationDTO(c *Conversation) ConversationDTO {
	return ConversationDTO{
		ID:            c.ID,
		UserID:        c.UserID,
		ModelID:       c.ModelID,
		SystemPrompt:  c.SystemPrompt,
		Title:         c.Title,
		ProjectID:     c.ProjectID,
		WorkspaceID:   c.WorkspaceID,
		IssueID:       c.IssueID,
		RequirementID: c.RequirementID,
		CreatedAt:     c.CreatedAt,
		UpdatedAt:     c.UpdatedAt,
	}
}

func toMessageDTO(m *Message) MessageDTO {
	return MessageDTO{
		ID:               m.ID,
		ConversationID:   m.ConversationID,
		Role:             string(m.Role),
		Content:          m.Content,
		Thinking:         m.Thinking,
		Status:           string(m.Status),
		ErrorMessage:     m.ErrorMessage,
		PromptTokens:     m.PromptTokens,
		CompletionTokens: m.CompletionTokens,
		ThinkingTokens:   m.ThinkingTokens,
		Attachments:      toAttachmentDTOs(m.Attachments),
		CreatedAt:        m.CreatedAt,
		UpdatedAt:        m.UpdatedAt,
	}
}

// toAttachmentDTOs maps a slice of Attachment to DTOs, always returning a
// non-nil (possibly empty) slice so the JSON field serializes as [].
func toAttachmentDTOs(atts []Attachment) []AttachmentDTO {
	out := make([]AttachmentDTO, 0, len(atts))
	for _, a := range atts {
		out = append(out, AttachmentDTO{
			ID:        a.ID,
			Filename:  a.Filename,
			MimeType:  a.MimeType,
			SizeBytes: a.SizeBytes,
			SHA256:    a.SHA256,
			CreatedAt: a.CreatedAt,
		})
	}
	return out
}

func toTemplateDTO(t *PromptTemplate) TemplateDTO {
	return TemplateDTO{
		ID:        t.ID,
		Name:      t.Name,
		Content:   t.Content,
		Scope:     string(t.Scope),
		OwnerID:   t.OwnerID,
		CreatedAt: t.CreatedAt,
		UpdatedAt: t.UpdatedAt,
	}
}

func toEndpointDTO(ep *LLMEndpoint) EndpointDTO {
	return EndpointDTO{
		ID:          ep.ID,
		Provider:    string(ep.Provider),
		DisplayName: ep.DisplayName,
		BaseURL:     ep.BaseURL,
		CreatedBy:   ep.CreatedBy,
		CreatedAt:   ep.CreatedAt,
		UpdatedAt:   ep.UpdatedAt,
	}
}

func toModelDTO(m *LLMModel) ModelDTO {
	return ModelDTO{
		ID:                           m.ID,
		EndpointID:                   m.EndpointID,
		ModelID:                      m.ModelID,
		DisplayName:                  m.DisplayName,
		Capabilities:                 m.Capabilities,
		ContextWindow:                m.ContextWindow,
		MaxOutputTokens:              m.MaxOutputTokens,
		PromptPricePerMillionUSD:     m.PromptPricePerMillionUSD,
		CompletionPricePerMillionUSD: m.CompletionPricePerMillionUSD,
		ThinkingPricePerMillionUSD:   m.ThinkingPricePerMillionUSD,
		IsTitleGenerator:             m.IsTitleGenerator,
		Enabled:                      m.Enabled,
		SortOrder:                    m.SortOrder,
		CreatedAt:                    m.CreatedAt,
		UpdatedAt:                    m.UpdatedAt,
	}
}
