package acp

import (
	"encoding/json"
	"time"

	"github.com/google/uuid"
)

// AgentKindAdminDTO 是 admin 视图的完整字段。EnvKeys 仅返回 key 列表（不返回值）。
type AgentKindAdminDTO struct {
	ID            uuid.UUID `json:"id"`
	Name          string    `json:"name"`
	DisplayName   string    `json:"display_name"`
	Description   string    `json:"description"`
	BinaryPath    string    `json:"binary_path"`
	Args          []string  `json:"args"`
	EnvKeys       []string  `json:"env_keys"`
	Enabled       bool      `json:"enabled"`
	ToolAllowlist []string  `json:"tool_allowlist"`
	ClientType    string    `json:"client_type"`
	// MCPServers 明文返回（admin only，编辑所需）；条目可能含 header/env 密钥。
	MCPServers []McpServerSpec `json:"mcp_servers"`
	// 成本核算：model 价格来源 + 默认预算上限（均可空）。
	ModelID             *string   `json:"model_id"`
	MaxCostUSD          *float64  `json:"max_cost_usd"`
	MaxTokens           *int64    `json:"max_tokens"`
	MaxWallClockSeconds *int32    `json:"max_wall_clock_seconds"`
	CreatedBy           uuid.UUID `json:"created_by"`
	CreatedAt           string    `json:"created_at"`
	UpdatedAt           string    `json:"updated_at"`
}

// AgentKindPublicDTO 是普通用户视图，不暴露 binary_path / args / env_keys。
type AgentKindPublicDTO struct {
	ID          uuid.UUID `json:"id"`
	Name        string    `json:"name"`
	DisplayName string    `json:"display_name"`
	Enabled     bool      `json:"enabled"`
}

// CreateAgentKindReq / UpdateAgentKindReq 是 HTTP 请求体。
type CreateAgentKindReq struct {
	Name          string            `json:"name"`
	DisplayName   string            `json:"display_name"`
	Description   string            `json:"description"`
	BinaryPath    string            `json:"binary_path"`
	Args          []string          `json:"args"`
	Env           map[string]string `json:"env"`
	Enabled       *bool             `json:"enabled"`
	ToolAllowlist []string          `json:"tool_allowlist"`
	ClientType    string            `json:"client_type"`
	MCPServers    []McpServerSpec   `json:"mcp_servers"`
	// 成本核算：model_id 为字符串 UUID（空/缺省 = 不设置）；预算上限均可选。
	ModelID             *string  `json:"model_id"`
	MaxCostUSD          *float64 `json:"max_cost_usd"`
	MaxTokens           *int64   `json:"max_tokens"`
	MaxWallClockSeconds *int32   `json:"max_wall_clock_seconds"`
}

type UpdateAgentKindReq struct {
	DisplayName   *string           `json:"display_name,omitempty"`
	Description   *string           `json:"description,omitempty"`
	BinaryPath    *string           `json:"binary_path,omitempty"`
	Args          []string          `json:"args,omitempty"`
	Env           map[string]string `json:"env,omitempty"`
	Enabled       *bool             `json:"enabled,omitempty"`
	ToolAllowlist []string          `json:"tool_allowlist,omitempty"`
	ClientType    *string           `json:"client_type,omitempty"`
	MCPServers    []McpServerSpec   `json:"mcp_servers,omitempty"` // nil = 不改；非 nil（含空）= 替换
	// 成本核算三态：字段存在（非 nil）= 设置；缺省（nil）= 不改。
	// ModelID 空串 = 清空；预算上限值 <=0 = 清空。
	ModelID             *string  `json:"model_id,omitempty"`
	MaxCostUSD          *float64 `json:"max_cost_usd,omitempty"`
	MaxTokens           *int64   `json:"max_tokens,omitempty"`
	MaxWallClockSeconds *int32   `json:"max_wall_clock_seconds,omitempty"`
}

// ConfigFileDTO 是 AgentKind 配置文件的对外视图（admin only，content 明文）。
type ConfigFileDTO struct {
	RelPath   string `json:"rel_path"`
	Content   string `json:"content"`
	UpdatedAt string `json:"updated_at"`
}

// UpsertConfigFileReq 是 PUT config-files 请求体。
type UpsertConfigFileReq struct {
	RelPath string `json:"rel_path"`
	Content string `json:"content"`
}

func configFileToDTO(f *ConfigFileContent) ConfigFileDTO {
	return ConfigFileDTO{
		RelPath:   f.RelPath,
		Content:   f.Content,
		UpdatedAt: f.UpdatedAt.UTC().Format("2006-01-02T15:04:05Z"),
	}
}

// PermissionRequestDTO 是权限请求的对外视图。
type PermissionRequestDTO struct {
	ID        string          `json:"id"`
	SessionID string          `json:"session_id"`
	ToolName  string          `json:"tool_name"`
	ToolCall  json.RawMessage `json:"tool_call"`
	Options   json.RawMessage `json:"options"`
	Status    string          `json:"status"`
	CreatedAt string          `json:"created_at"`
}

func permissionRequestToDTO(p *PermissionRequest) PermissionRequestDTO {
	return PermissionRequestDTO{
		ID:        p.ID.String(),
		SessionID: p.SessionID.String(),
		ToolName:  p.ToolName,
		ToolCall:  json.RawMessage(p.ToolCall),
		Options:   json.RawMessage(p.Options),
		Status:    string(p.Status),
		CreatedAt: p.CreatedAt.Format(time.RFC3339),
	}
}

// CreateSessionReq is the request body for POST /api/v1/acp/sessions.
type CreateSessionReq struct {
	WorkspaceID       string  `json:"workspace_id"`
	AgentKindID       string  `json:"agent_kind_id"`
	Branch            *string `json:"branch,omitempty"`
	IssueNumber       *int    `json:"issue_number,omitempty"`
	RequirementNumber *int    `json:"requirement_number,omitempty"`
	InitialPrompt     *string `json:"initial_prompt,omitempty"`
}

// SessionDTO is the response shape for sessions.
type SessionDTO struct {
	ID             string  `json:"id"`
	WorkspaceID    string  `json:"workspace_id"`
	ProjectID      string  `json:"project_id"`
	AgentKindID    string  `json:"agent_kind_id"`
	UserID         string  `json:"user_id"`
	IssueID        *string `json:"issue_id"`
	RequirementID  *string `json:"requirement_id"`
	AgentSessionID *string `json:"agent_session_id"`
	Branch         string  `json:"branch"`
	CwdPath        string  `json:"cwd_path"`
	IsMainWorktree bool    `json:"is_main_worktree"`
	Status         string  `json:"status"`
	PID            *int32  `json:"pid"`
	ExitCode       *int32  `json:"exit_code"`
	LastError      *string `json:"last_error"`
	StartedAt      string  `json:"started_at"`
	EndedAt        *string `json:"ended_at"`
	// 成本核算：运行时累计 + 有效预算上限 + 终止原因。
	PromptTokens              int64    `json:"prompt_tokens"`
	CompletionTokens          int64    `json:"completion_tokens"`
	ThinkingTokens            int64    `json:"thinking_tokens"`
	TotalCostUSD              float64  `json:"total_cost_usd"`
	BudgetMaxCostUSD          *float64 `json:"budget_max_cost_usd"`
	BudgetMaxTokens           *int64   `json:"budget_max_tokens"`
	BudgetMaxWallClockSeconds *int32   `json:"budget_max_wall_clock_seconds"`
	TerminatedReason          *string  `json:"terminated_reason"`
}

func sessionToDTO(s *Session) SessionDTO {
	var issueID, reqID, ended *string
	if s.IssueID != nil {
		v := s.IssueID.String()
		issueID = &v
	}
	if s.RequirementID != nil {
		v := s.RequirementID.String()
		reqID = &v
	}
	if s.EndedAt != nil {
		v := s.EndedAt.UTC().Format("2006-01-02T15:04:05Z")
		ended = &v
	}
	return SessionDTO{
		ID:             s.ID.String(),
		WorkspaceID:    s.WorkspaceID.String(),
		ProjectID:      s.ProjectID.String(),
		AgentKindID:    s.AgentKindID.String(),
		UserID:         s.UserID.String(),
		IssueID:        issueID,
		RequirementID:  reqID,
		AgentSessionID: s.AgentSessionID,
		Branch:         s.Branch,
		CwdPath:        s.CwdPath,
		IsMainWorktree: s.IsMainWorktree,
		Status:         string(s.Status),
		PID:            s.PID,
		ExitCode:       s.ExitCode,
		LastError:      s.LastError,
		StartedAt:      s.StartedAt.UTC().Format("2006-01-02T15:04:05Z"),
		EndedAt:        ended,

		PromptTokens:              s.PromptTokens,
		CompletionTokens:          s.CompletionTokens,
		ThinkingTokens:            s.ThinkingTokens,
		TotalCostUSD:              s.TotalCostUSD,
		BudgetMaxCostUSD:          s.BudgetMaxCostUSD,
		BudgetMaxTokens:           s.BudgetMaxTokens,
		BudgetMaxWallClockSeconds: s.BudgetMaxWallClockSeconds,
		TerminatedReason:          s.TerminatedReason,
	}
}

// SessionUsageDTO 是单条 per-turn 账目的对外视图。
type SessionUsageDTO struct {
	ID               int64   `json:"id"`
	ModelID          *string `json:"model_id"`
	PromptTokens     int64   `json:"prompt_tokens"`
	CompletionTokens int64   `json:"completion_tokens"`
	ThinkingTokens   int64   `json:"thinking_tokens"`
	CostUSD          float64 `json:"cost_usd"`
	CreatedAt        string  `json:"created_at"`
}

// SessionUsageResponse 是 GET /sessions/{id}/usage 的响应：会话累计 + 最近账目。
type SessionUsageResponse struct {
	SessionID        string            `json:"session_id"`
	PromptTokens     int64             `json:"prompt_tokens"`
	CompletionTokens int64             `json:"completion_tokens"`
	ThinkingTokens   int64             `json:"thinking_tokens"`
	TotalCostUSD     float64           `json:"total_cost_usd"`
	BudgetMaxCostUSD *float64          `json:"budget_max_cost_usd"`
	BudgetMaxTokens  *int64            `json:"budget_max_tokens"`
	Recent           []SessionUsageDTO `json:"recent"`
}

// AcpUsageItem 是 admin ACP 用量聚合的一行（镜像 chat AdminUsageItem）。
type AcpUsageItem struct {
	Key              string  `json:"key"`
	PromptTokens     int64   `json:"prompt_tokens"`
	CompletionTokens int64   `json:"completion_tokens"`
	ThinkingTokens   int64   `json:"thinking_tokens"`
	CostUSD          float64 `json:"cost_usd"`
}

// AcpUsageResponse 包裹分组用量项。
type AcpUsageResponse struct {
	Items []AcpUsageItem `json:"items"`
}

// ===== run-history dashboard DTO =====

// DashboardResponse 是 GET /api/v1/acp/dashboard 的响应：总览 + 按天序列。
type DashboardResponse struct {
	From   string           `json:"from"`
	To     string           `json:"to"`
	Rollup SessionRollupDTO `json:"rollup"`
	ByDay  []SessionDayDTO  `json:"by_day"`
}

// SessionRollupDTO 是会话总览（计数 + 成功率 + 成本 + 平均时长）。
type SessionRollupDTO struct {
	Total              int64   `json:"total"`
	Succeeded          int64   `json:"succeeded"`
	Crashed            int64   `json:"crashed"`
	Active             int64   `json:"active"`
	SuccessRate        float64 `json:"success_rate"`
	TotalCostUSD       float64 `json:"total_cost_usd"`
	TotalTokens        int64   `json:"total_tokens"`
	AvgDurationSeconds float64 `json:"avg_duration_seconds"`
}

// SessionDayDTO 是按天的时间序列一行。
type SessionDayDTO struct {
	Day          string  `json:"day"`
	Total        int64   `json:"total"`
	Succeeded    int64   `json:"succeeded"`
	Crashed      int64   `json:"crashed"`
	TotalCostUSD float64 `json:"total_cost_usd"`
}

// SessionTimelineDTO 是单会话事件时间线一行（按 method/kind 分桶）。
type SessionTimelineDTO struct {
	Direction  string `json:"direction"`
	Kind       string `json:"kind"`
	Method     string `json:"method"`
	EventCount int64  `json:"event_count"`
	FirstAt    string `json:"first_at"`
	LastAt     string `json:"last_at"`
}

func dashboardToResponse(r *DashboardResult) DashboardResponse {
	resp := DashboardResponse{
		From: r.From.UTC().Format(time.RFC3339),
		To:   r.To.UTC().Format(time.RFC3339),
		Rollup: SessionRollupDTO{
			Total:              r.Rollup.Total,
			Succeeded:          r.Rollup.Succeeded,
			Crashed:            r.Rollup.Crashed,
			Active:             r.Rollup.Active,
			SuccessRate:        r.Rollup.SuccessRate(),
			TotalCostUSD:       r.Rollup.TotalCostUSD,
			TotalTokens:        r.Rollup.TotalTokens,
			AvgDurationSeconds: r.Rollup.AvgDurationSeconds,
		},
		ByDay: make([]SessionDayDTO, 0, len(r.ByDay)),
	}
	for _, d := range r.ByDay {
		resp.ByDay = append(resp.ByDay, SessionDayDTO{
			Day:          d.Day.UTC().Format(time.RFC3339),
			Total:        d.Total,
			Succeeded:    d.Succeeded,
			Crashed:      d.Crashed,
			TotalCostUSD: d.TotalCostUSD,
		})
	}
	return resp
}

func sessionTimelineToDTO(b SessionTimelineBucket) SessionTimelineDTO {
	return SessionTimelineDTO{
		Direction:  b.Direction,
		Kind:       b.RPCKind,
		Method:     b.Method,
		EventCount: b.EventCount,
		FirstAt:    b.FirstAt.UTC().Format(time.RFC3339),
		LastAt:     b.LastAt.UTC().Format(time.RFC3339),
	}
}

func sessionUsageToDTO(r *SessionUsageRecord) SessionUsageDTO {
	var modelID *string
	if r.ModelID != nil {
		v := r.ModelID.String()
		modelID = &v
	}
	return SessionUsageDTO{
		ID:               r.ID,
		ModelID:          modelID,
		PromptTokens:     r.PromptTokens,
		CompletionTokens: r.CompletionTokens,
		ThinkingTokens:   r.ThinkingTokens,
		CostUSD:          r.CostUSD,
		CreatedAt:        r.CreatedAt.UTC().Format(time.RFC3339),
	}
}
