// mcp_bridge.go 实现 mcp.ACPBridge：把 mcp 的 acp-free DTO 转译到本包
// service 调用。放在 acp 包内（acp 已 import mcp，转译逻辑贴近领域类型），
// 避免 mcp → acp 的循环依赖。
package acp

import (
	"context"

	"github.com/google/uuid"

	"github.com/yan1h/agent-coding-workflow/internal/mcp"
)

// MCPBridge 适配 AgentKind/Session/Permission 三个服务到 mcp.ACPBridge。
// repo 仅用于只读的回合列表（ListSessionTurns）——scope 校验先经 sessions.Get 完成。
type MCPBridge struct {
	kinds    AgentKindService
	sessions SessionService
	perms    *PermissionService
	repo     Repository
}

// NewMCPBridge 构造桥接适配器，由 app.go 装配 mcp.ServerDeps 时调用。
func NewMCPBridge(kinds AgentKindService, sessions SessionService, perms *PermissionService, repo Repository) *MCPBridge {
	return &MCPBridge{kinds: kinds, sessions: sessions, perms: perms, repo: repo}
}

var _ mcp.ACPBridge = (*MCPBridge)(nil)

func (b *MCPBridge) ListAgentKinds(ctx context.Context, userID uuid.UUID, isAdmin bool) ([]mcp.ACPAgentKind, error) {
	ks, err := b.kinds.List(ctx, Caller{UserID: userID, IsAdmin: isAdmin})
	if err != nil {
		return nil, err
	}
	out := make([]mcp.ACPAgentKind, 0, len(ks))
	for _, k := range ks {
		out = append(out, agentKindToMCP(k))
	}
	return out, nil
}

func (b *MCPBridge) GetAgentKind(ctx context.Context, userID uuid.UUID, isAdmin bool, id uuid.UUID) (*mcp.ACPAgentKind, error) {
	k, err := b.kinds.Get(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, id)
	if err != nil {
		return nil, err
	}
	out := agentKindToMCP(k)
	return &out, nil
}

func (b *MCPBridge) CreateSession(ctx context.Context, userID uuid.UUID, isAdmin bool, in mcp.ACPCreateSessionInput) (*mcp.ACPSession, error) {
	s, err := b.sessions.Create(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, CreateSessionInput{
		WorkspaceID:       in.WorkspaceID,
		AgentKindID:       in.AgentKindID,
		Branch:            in.Branch,
		IssueNumber:       in.IssueNumber,
		RequirementNumber: in.RequirementNumber,
		InitialPrompt:     in.InitialPrompt,
	})
	if err != nil {
		return nil, err
	}
	out := sessionToMCP(s)
	return &out, nil
}

func (b *MCPBridge) GetSession(ctx context.Context, userID uuid.UUID, isAdmin bool, id uuid.UUID) (*mcp.ACPSession, error) {
	s, err := b.sessions.Get(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, id)
	if err != nil {
		return nil, err
	}
	out := sessionToMCP(s)
	return &out, nil
}

func (b *MCPBridge) ListSessions(ctx context.Context, userID uuid.UUID, isAdmin bool, f mcp.ACPSessionFilter) ([]mcp.ACPSession, error) {
	ss, err := b.sessions.List(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, SessionListFilter{
		All:           f.All,
		RequirementID: f.RequirementID,
	})
	if err != nil {
		return nil, err
	}
	out := make([]mcp.ACPSession, 0, len(ss))
	for _, s := range ss {
		out = append(out, sessionToMCP(s))
	}
	return out, nil
}

func (b *MCPBridge) TerminateSession(ctx context.Context, userID uuid.UUID, isAdmin bool, id uuid.UUID) error {
	return b.sessions.Terminate(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, id)
}

func (b *MCPBridge) ListPendingPermissions(ctx context.Context, userID uuid.UUID, isAdmin bool, sessionID uuid.UUID) ([]mcp.ACPPermission, error) {
	ps, err := b.perms.ListPendingBySession(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, sessionID)
	if err != nil {
		return nil, err
	}
	out := make([]mcp.ACPPermission, 0, len(ps))
	for _, p := range ps {
		out = append(out, mcp.ACPPermission{
			ID:             p.ID,
			SessionID:      p.SessionID,
			AgentRequestID: p.AgentRequestID,
			ToolName:       p.ToolName,
			Status:         string(p.Status),
			CreatedAt:      p.CreatedAt,
		})
	}
	return out, nil
}

// ListPendingApprovals 返回调用者跨所有会话的待审权限请求（HITL inbox，read-only）。
func (b *MCPBridge) ListPendingApprovals(ctx context.Context, userID uuid.UUID, isAdmin bool) ([]mcp.ACPPermission, error) {
	ps, err := b.perms.ListPendingForUser(ctx, Caller{UserID: userID, IsAdmin: isAdmin})
	if err != nil {
		return nil, err
	}
	out := make([]mcp.ACPPermission, 0, len(ps))
	for _, p := range ps {
		out = append(out, mcp.ACPPermission{
			ID:             p.ID,
			SessionID:      p.SessionID,
			AgentRequestID: p.AgentRequestID,
			ToolName:       p.ToolName,
			Status:         string(p.Status),
			CreatedAt:      p.CreatedAt,
		})
	}
	return out, nil
}

// ListSessionTurns 返回会话的回合列表（只读）。先经 sessions.Get 做用户 + 项目
// scope 校验（与 GetSession 同语义），再用 repo 读 acp_turns。
func (b *MCPBridge) ListSessionTurns(ctx context.Context, userID uuid.UUID, isAdmin bool, sessionID uuid.UUID) ([]mcp.ACPTurn, error) {
	if _, err := b.sessions.Get(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, sessionID); err != nil {
		return nil, err
	}
	ts, err := b.repo.ListTurnsBySession(ctx, sessionID)
	if err != nil {
		return nil, err
	}
	out := make([]mcp.ACPTurn, 0, len(ts))
	for _, t := range ts {
		out = append(out, mcp.ACPTurn{
			TurnIndex:   t.TurnIndex,
			Status:      string(t.Status),
			StopReason:  t.StopReason,
			UpdateCount: t.UpdateCount,
			StartedAt:   t.StartedAt,
			CompletedAt: t.CompletedAt,
		})
	}
	return out, nil
}

// GetRunDashboard 返回 run-history 汇总（owner scope；admin 全量，read-only）。
func (b *MCPBridge) GetRunDashboard(ctx context.Context, userID uuid.UUID, isAdmin bool, in mcp.ACPRunDashboardInput) (*mcp.ACPRunDashboard, error) {
	res, err := b.sessions.Dashboard(ctx, Caller{UserID: userID, IsAdmin: isAdmin}, DashboardInput{
		ProjectID:     in.ProjectID,
		RequirementID: in.RequirementID,
		From:          in.From,
		To:            in.To,
	})
	if err != nil {
		return nil, err
	}
	out := &mcp.ACPRunDashboard{
		From:               res.From,
		To:                 res.To,
		Total:              res.Rollup.Total,
		Succeeded:          res.Rollup.Succeeded,
		Crashed:            res.Rollup.Crashed,
		Active:             res.Rollup.Active,
		SuccessRate:        res.Rollup.SuccessRate(),
		TotalCostUSD:       res.Rollup.TotalCostUSD,
		TotalTokens:        res.Rollup.TotalTokens,
		AvgDurationSeconds: res.Rollup.AvgDurationSeconds,
		ByDay:              make([]mcp.ACPRunDayRow, 0, len(res.ByDay)),
	}
	for _, d := range res.ByDay {
		out.ByDay = append(out.ByDay, mcp.ACPRunDayRow{
			Day:          d.Day,
			Total:        d.Total,
			Succeeded:    d.Succeeded,
			Crashed:      d.Crashed,
			TotalCostUSD: d.TotalCostUSD,
		})
	}
	return out, nil
}

func agentKindToMCP(k *AgentKind) mcp.ACPAgentKind {
	return mcp.ACPAgentKind{
		ID:            k.ID,
		Name:          k.Name,
		DisplayName:   k.DisplayName,
		Description:   k.Description,
		Enabled:       k.Enabled,
		ToolAllowlist: k.ToolAllowlist,
	}
}

func sessionToMCP(s *Session) mcp.ACPSession {
	return mcp.ACPSession{
		ID:               s.ID,
		WorkspaceID:      s.WorkspaceID,
		ProjectID:        s.ProjectID,
		AgentKindID:      s.AgentKindID,
		UserID:           s.UserID,
		IssueID:          s.IssueID,
		RequirementID:    s.RequirementID,
		Branch:           s.Branch,
		IsMainWorktree:   s.IsMainWorktree,
		Status:           string(s.Status),
		LastError:        s.LastError,
		LastStopReason:   s.LastStopReason,
		StartedAt:        s.StartedAt,
		EndedAt:          s.EndedAt,
		PromptTokens:     s.PromptTokens,
		CompletionTokens: s.CompletionTokens,
		ThinkingTokens:   s.ThinkingTokens,
		TotalCostUSD:     s.TotalCostUSD,
		BudgetMaxCostUSD: s.BudgetMaxCostUSD,
		BudgetMaxTokens:  s.BudgetMaxTokens,
	}
}
