import { buildArbiterContextPrompt } from './arbiter-context.js';
import { formatMessages } from './router.js';
import type { NewMessage, PairedTask, PairedTurnOutput } from './types.js';

const CARRIED_FORWARD_OWNER_FINAL_MARKER =
  '[Carried forward context from the previous task: latest owner final]';

const CARRIED_FORWARD_OWNER_FINAL_GUIDANCE = `System note:
If you see a message beginning with "${CARRIED_FORWARD_OWNER_FINAL_MARKER}", treat it as background only. Do not repeat, continue, or answer that carried-forward final directly. Respond only to the latest human request and the current task.`;

export interface PriorTaskPromptContext {
  ownerFinal?: string | null;
  reviewerFinal?: string | null;
}

function turnOutputsToMessages(
  outputs: PairedTurnOutput[],
  chatJid: string,
): NewMessage[] {
  return outputs.map((turnOutput) => ({
    id: `turn-${turnOutput.task_id}-${turnOutput.turn_number}`,
    chat_jid: chatJid,
    sender: turnOutput.role,
    sender_name: turnOutput.role,
    content: turnOutput.output_text,
    timestamp: turnOutput.created_at,
    is_bot_message: true as const,
    is_from_me: false as const,
  }));
}

function mergeHumanAndTurnOutputMessages(
  chatJid: string,
  humanMessages: NewMessage[],
  turnOutputs: PairedTurnOutput[],
): NewMessage[] {
  return [
    ...humanMessages,
    ...turnOutputsToMessages(turnOutputs, chatJid),
  ].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
}

function hasCarriedForwardOwnerFinal(outputs: PairedTurnOutput[]): boolean {
  return outputs.some((output) =>
    output.output_text.startsWith(CARRIED_FORWARD_OWNER_FINAL_MARKER),
  );
}

function prependCarriedForwardGuidance(
  prompt: string,
  turnOutputs: PairedTurnOutput[],
): string {
  if (!hasCarriedForwardOwnerFinal(turnOutputs)) {
    return prompt;
  }
  return `${CARRIED_FORWARD_OWNER_FINAL_GUIDANCE}\n\n${prompt}`;
}

function truncatePriorTaskFinal(text: string, maxChars = 1200): string {
  const normalized = text.trim();
  if (normalized.length <= maxChars) {
    return normalized;
  }
  return `${normalized.slice(0, maxChars)}...`;
}

function formatPriorTaskPromptContext(
  priorTaskContext?: PriorTaskPromptContext | null,
): string {
  if (!priorTaskContext) {
    return '';
  }

  const sections: string[] = [];
  if (priorTaskContext.ownerFinal?.trim()) {
    sections.push(
      `Previous task owner final:\n---\n${truncatePriorTaskFinal(priorTaskContext.ownerFinal)}\n---`,
    );
  }
  if (priorTaskContext.reviewerFinal?.trim()) {
    sections.push(
      `Previous task reviewer final:\n---\n${truncatePriorTaskFinal(priorTaskContext.reviewerFinal)}\n---`,
    );
  }

  if (sections.length === 0) {
    return '';
  }

  return `Background from the previous completed paired task:\n${sections.join('\n\n')}\n\n`;
}

export function buildPairedTurnPrompt(args: {
  taskId: string;
  chatJid: string;
  timezone: string;
  missedMessages: NewMessage[];
  labeledFallbackMessages: NewMessage[];
  turnOutputs: PairedTurnOutput[];
}): string {
  if (args.turnOutputs.length === 0) {
    return formatMessages(args.labeledFallbackMessages, args.timezone);
  }

  const humanMessages = args.missedMessages.filter(
    (message) => !message.is_bot_message,
  );
  return prependCarriedForwardGuidance(
    formatMessages(
      mergeHumanAndTurnOutputMessages(
        args.chatJid,
        humanMessages,
        args.turnOutputs,
      ),
      args.timezone,
    ),
    args.turnOutputs,
  );
}

export function buildReviewerPendingPrompt(args: {
  chatJid: string;
  timezone: string;
  turnOutputs: PairedTurnOutput[];
  recentHumanMessages: NewMessage[];
  lastHumanMessage: string | null | undefined;
  priorTaskContext?: PriorTaskPromptContext | null;
}): string {
  if (args.turnOutputs.length > 0) {
    return prependCarriedForwardGuidance(
      formatMessages(
        mergeHumanAndTurnOutputMessages(
          args.chatJid,
          args.recentHumanMessages,
          args.turnOutputs,
        ),
        args.timezone,
      ),
      args.turnOutputs,
    );
  }

  if (!args.lastHumanMessage) {
    return `${formatPriorTaskPromptContext(args.priorTaskContext)}Review the latest owner changes in the workspace.`;
  }

  return `${formatPriorTaskPromptContext(args.priorTaskContext)}User request:\n---\n${args.lastHumanMessage}\n---\n\nReview the latest owner changes in the workspace.`;
}

export function buildOwnerPendingPrompt(args: {
  chatJid: string;
  timezone: string;
  turnOutputs: PairedTurnOutput[];
  recentHumanMessages: NewMessage[];
  lastHumanMessage: string | null | undefined;
  priorTaskContext?: PriorTaskPromptContext | null;
}): string {
  if (args.turnOutputs.length > 0) {
    return prependCarriedForwardGuidance(
      formatMessages(
        mergeHumanAndTurnOutputMessages(
          args.chatJid,
          args.recentHumanMessages,
          args.turnOutputs,
        ),
        args.timezone,
      ),
      args.turnOutputs,
    );
  }

  if (!args.lastHumanMessage) {
    return `${formatPriorTaskPromptContext(args.priorTaskContext)}Continue the owner turn using the latest reviewer or arbiter feedback.`;
  }

  return `${formatPriorTaskPromptContext(args.priorTaskContext)}User request:\n---\n${args.lastHumanMessage}\n---\n\nContinue the owner turn using the latest reviewer or arbiter feedback.`;
}

export function buildArbiterPromptForTask(args: {
  task: PairedTask;
  chatJid: string;
  timezone: string;
  turnOutputs: PairedTurnOutput[];
  recentMessages: NewMessage[];
  labeledRecentMessages: NewMessage[];
}): string {
  const messages =
    args.turnOutputs.length > 0
      ? mergeHumanAndTurnOutputMessages(
          args.chatJid,
          args.recentMessages.filter((message) => !message.is_bot_message),
          args.turnOutputs,
        )
      : args.labeledRecentMessages;

  return buildArbiterContextPrompt({
    chatJid: args.chatJid,
    taskId: args.task.id,
    roundTripCount: args.task.round_trip_count,
    timezone: args.timezone,
    messages,
  });
}

export function buildFinalizePendingPrompt(args: {
  turnOutputs: PairedTurnOutput[];
}): string {
  const lastReviewerOutput = [...args.turnOutputs]
    .reverse()
    .find((output) => output.role === 'reviewer');
  const reviewerSummary = lastReviewerOutput?.output_text
    ? `\n\nReviewer's final assessment:\n${lastReviewerOutput.output_text.slice(0, 2000)}`
    : '';

  return `The reviewer approved your work (DONE). Finalize and report the result.
If you intend to close this paired turn now, your first line must be DONE.
If your first line is DONE_WITH_CONCERNS, the system will reopen review instead of finishing.${reviewerSummary}`;
}
