package agent

import (
	"context"
	"io"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/drivercontract"
	"github.com/tidbcloud/AgentTeam/desktop/internal/consts"
	"github.com/tidbcloud/AgentTeam/internal/core/rewindcaps"
)

const codexAppServerRecoveryStrategy = rewindcaps.StrategyCodexAppServerTurns

const codexAppServerMaxMessageBytes = 32 * 1024 * 1024

const codexInterruptPollInterval = 50 * time.Millisecond

const codexActiveInterruptSnapshotTTL = 30 * time.Second

type reasoningSectionState struct {
	text  string
	title string
}

type activeInterruptSnapshot struct {
	threadID                 string
	beforeCompletedTurnCount int
	interruptedTurnID        string
	recordedAt               time.Time
}

type inFlightServerRequest struct {
	cancel     context.CancelFunc
	method     string
	threadID   string
	generation uint64
}

type toolActivityRef struct {
	threadID string
	turnID   string
	callID   string
	toolName string
	started  bool
}

func (d *CodexAppServerDriver) currentLaunchConfig() drivercontract.LaunchConfig {
	d.mu.Lock()
	defer d.mu.Unlock()
	return drivercontract.LaunchConfig{
		PermissionMode:  d.launchPermissionMode,
		WorkDir:         d.launchWorkDir,
		Model:           d.launchModel,
		CompiledPrompt:  d.launchPromptCarrier,
		ReasoningEffort: d.reasoningEffort,
	}
}

// Name returns the runtime identifier used by profile and dispatcher config.
func (d *CodexAppServerDriver) Name() string { return "codex" }

// SupportsStdinNotification reports that codex-app-server supports stdin nudges.
func (d *CodexAppServerDriver) SupportsStdinNotification() bool { return true }

// MCPToolPrefix returns the runtime-specific MCP tool prefix.
func (d *CodexAppServerDriver) MCPToolPrefix() string { return "mcp__agentteam__" }

// ---------------------------------------------------------------------------
// Spawn
// ---------------------------------------------------------------------------

// Spawn launches the Codex App Server and writes the initial prompt.
func (d *CodexAppServerDriver) Spawn(ctx context.Context, cfg drivercontract.LaunchConfig) (drivercontract.SpawnResult, error) {
	carrier, err := cfg.RequireCompiledPrompt()
	if err != nil {
		return drivercontract.SpawnResult{}, err
	}
	cfg.CompiledPrompt = carrier
	pipeReader, writer := io.Pipe()
	reader := newCodexTranslatedReader(pipeReader)
	cmd, stdin, cleanup, wait, err := d.startTransport(ctx, cfg, writer, reader.consumed)
	if err != nil {
		logIgnoredCleanupError("failed to close codex startup writer pipe", writer.Close())
		logIgnoredCleanupError("failed to close codex startup reader pipe", reader.Close())
		return drivercontract.SpawnResult{}, err
	}
	defer func() {
		if err == nil {
			return
		}
		cleanup()
		logIgnoredCleanupError("failed to close codex startup writer pipe", writer.Close())
		logIgnoredCleanupError("failed to close codex startup reader pipe", reader.Close())
		go func() {
			logIgnoredCleanupError("failed waiting for codex process after startup cleanup", wait())
		}()
	}()

	threadID, initialTurnMethod, initialTurnParams, sessionResumed, err := d.prepareInitialThread(ctx, cfg)
	if err != nil {
		return drivercontract.SpawnResult{}, err
	}
	freshSessionFallback := d.takeSessionResumeFallback()

	preparedRecoveryPoint := prepareSpawnRecoveryPoint(d, cfg.InitialDeliveryMessageID, threadID)

	d.enqueueTranslatedEvent(translatedEvent{
		Kind:      consts.ParsedEventKindSessionInit,
		SessionID: threadID,
	})
	if strings.TrimSpace(initialTurnMethod) != "" {
		err = d.sendTurnRequest(ctx, threadID, initialTurnMethod, initialTurnParams)
	}
	if err != nil {
		return drivercontract.SpawnResult{}, err
	}

	return drivercontract.SpawnResult{
		Cmd:                   cmd,
		Wait:                  wait,
		Terminate:             cleanup,
		Stdin:                 stdin,
		Stdout:                reader,
		SessionID:             threadID,
		SessionResumed:        sessionResumed,
		FreshSessionFallback:  freshSessionFallback,
		PreparedRecoveryPoint: preparedRecoveryPoint,
	}, nil
}

// ---------------------------------------------------------------------------
// Recovery
// ---------------------------------------------------------------------------

// RestoreRecoveryPointDetached performs detached recovery for codex-app-server.
