import { join } from "node:path";

import {
  findReportForTaskOnDisk,
  roleFromAgentId,
} from "../_internal/report-reconcile.ts";
import { findTaskPathById } from "../lifecycle/taskPathUtils.ts";
import {
  invokeFcopToolOnce,
  resolveOneShotPythonBin,
} from "./FcopMcpOneShot.ts";
import type { GoogleContractState } from "./FcopGoogleRuntimeContract.ts";

export type GoogleReportSettlementInput = {
  projectRoot: string;
  agentId: string;
  recipient?: string;
  taskId?: string;
  pinnedTaskId?: string;
  toolLog?: string[];
  failedToolNames?: string[];
  hitMaxRounds?: boolean;
  hadToolFailure?: boolean;
  hadWriteReport?: boolean;
  hadSubmitTask?: boolean;
  model?: string;
  provider?: "google";
  failureReason?: string;
  contractState?: GoogleContractState;
  pythonBin?: string;
  /** Test hook — bypasses subprocess invoke. */
  invokeFcop?: (
    toolName: string,
    args: Record<string, unknown>,
  ) => Promise<string>;
};

export type GoogleReportSettlementResult = {
  ok: boolean;
  status: "done" | "blocked" | "failed";
  reason?: string;
  autoReportWritten?: boolean;
  submitted?: boolean;
};

function extractReportIdFromToolOutput(text: string): string | null {
  const m = text.match(
    /\b(REPORT-\d{8}-\d{3,}-[A-Z0-9-]+(?:-to-[A-Z0-9-]+)?)\b/i,
  );
  return m?.[1] ?? null;
}

function resolveTaskId(input: GoogleReportSettlementInput): string | undefined {
  const raw = input.pinnedTaskId?.trim() || input.taskId?.trim();
  return raw || undefined;
}

function resolveReportRecipient(
  input: GoogleReportSettlementInput,
): string {
  if (input.recipient?.trim()) return input.recipient.trim();
  const role = roleFromAgentId(input.agentId);
  if (role === "PM" || role === "PLANNER" || role === "PUBLISHER") {
    return "ADMIN";
  }
  return "PM";
}

function deriveBlockedReason(input: GoogleReportSettlementInput): string {
  if (input.failureReason?.trim()) return input.failureReason.trim();
  const cs = input.contractState;
  if (cs?.stopReason === "model_not_found") return "model_not_found";
  if (cs?.stopReason === "function_response_misaligned") {
    return "function_response_misaligned";
  }
  if (cs?.stopReason === "hit_max_rounds" || input.hitMaxRounds) {
    return "hit_max_rounds";
  }
  if (cs?.stopReason === "zero_toolcall") return "zero_toolcall";
  if (cs?.stopReason === "invalid_agent_output") return "invalid_agent_output";
  if (input.hadToolFailure || (input.failedToolNames?.length ?? 0) > 0) {
    return "tool_failed";
  }
  return "no_valid_report";
}

function buildBlockedReportBody(
  input: GoogleReportSettlementInput,
  reason: string,
): string {
  const failed = input.failedToolNames ?? [];
  const toolLog = input.toolLog ?? [];
  const lines: string[] = [
    "# Google FCoP 合约结算 — blocked REPORT（自动生成）",
    "",
    "```yaml",
    "status: blocked",
    "blocker_type: google_fcop_contract_failure",
    "agent_provider: google",
    "auto_generated: true",
    "admin_action_required: true",
    `reason: ${reason}`,
    `failed_tool_names: [${failed.map((n) => `"${n}"`).join(", ")}]`,
    `hit_max_rounds: ${Boolean(input.hitMaxRounds)}`,
    "```",
    "",
    "## 摘要",
    "",
    `本 REPORT 由 Google Adapter ReportSettlement 自动生成，原因：\`${reason}\`。`,
  ];
  if (input.model) {
    lines.push("", `模型：\`${input.model}\``);
  }
  if (toolLog.length > 0) {
    lines.push("", "## 工具调用记录（节选）", "", ...toolLog.slice(-20));
  }
  return lines.join("\n");
}

async function defaultInvokeFcop(
  input: GoogleReportSettlementInput,
  toolName: string,
  args: Record<string, unknown>,
): Promise<string> {
  const bin =
    input.pythonBin ??
    resolveOneShotPythonBin({
      command: process.env.PYTHON_BIN || "python",
      env: process.env as Record<string, string | undefined>,
    });
  return invokeFcopToolOnce(bin, input.projectRoot, toolName, args);
}

export async function settleGoogleFcopRun(
  input: GoogleReportSettlementInput,
): Promise<GoogleReportSettlementResult> {
  const taskId = resolveTaskId(input);
  if (!taskId) {
    return {
      ok: false,
      status: "failed",
      reason: "missing_task_id",
    };
  }

  const reporter = roleFromAgentId(input.agentId);
  const reportRecipient = resolveReportRecipient(input);
  const invoke =
    input.invokeFcop ??
    ((toolName, args) => defaultInvokeFcop(input, toolName, args));

  const hasReport = await findReportForTaskOnDisk({
    taskId,
    reporter,
    reportRecipient,
    projectRoot: input.projectRoot,
    fcopReportsDir: join(input.projectRoot, "fcop", "reports"),
  });

  const hadWriteReport =
    input.hadWriteReport ||
    input.contractState?.hadWriteReportSuccess ||
    hasReport;
  const hadSubmitTask =
    input.hadSubmitTask || input.contractState?.hadSubmitTaskSuccess;

  if (
    input.contractState?.stopReason === "write_report_submit_done" ||
    (hadWriteReport && hadSubmitTask)
  ) {
    return { ok: true, status: "done" };
  }

  if (hasReport && !hadSubmitTask) {
    const lifecycleRoot = join(input.projectRoot, "fcop", "_lifecycle");
    const located = await findTaskPathById(lifecycleRoot, taskId);
    if (located?.stage === "active") {
      try {
        await invoke("submit_task", {
          task_id: taskId,
          actor: reporter,
        });
        return { ok: true, status: "done", submitted: true };
      } catch (err) {
        const reason = "submit_task_failed";
        const body = buildBlockedReportBody(
          { ...input, failureReason: reason },
          reason,
        );
        try {
          await invoke("write_report", {
            task_id: taskId,
            reporter,
            recipient: reportRecipient,
            status: "blocked",
            body,
          });
          return {
            ok: false,
            status: "blocked",
            reason,
            autoReportWritten: true,
          };
        } catch {
          return { ok: false, status: "failed", reason };
        }
      }
    }
    return { ok: true, status: "done" };
  }

  if (!hasReport) {
    const reason = deriveBlockedReason(input);
    const body = buildBlockedReportBody(input, reason);
    try {
      const out = await invoke("write_report", {
        task_id: taskId,
        reporter,
        recipient: reportRecipient,
        status: "blocked",
        body,
      });
      const produced = extractReportIdFromToolOutput(out);
      if (!produced && !out.toLowerCase().includes("report")) {
        return {
          ok: false,
          status: "failed",
          reason: "auto_write_report_no_id",
        };
      }

      if (!hadSubmitTask) {
        const lifecycleRoot = join(input.projectRoot, "fcop", "_lifecycle");
        const located = await findTaskPathById(lifecycleRoot, taskId);
        if (located?.stage === "active") {
          try {
            await invoke("submit_task", {
              task_id: taskId,
              actor: reporter,
            });
            return {
              ok: false,
              status: "blocked",
              reason,
              autoReportWritten: true,
              submitted: true,
            };
          } catch {
            return {
              ok: false,
              status: "blocked",
              reason: "submit_task_failed",
              autoReportWritten: true,
            };
          }
        }
      }

      return {
        ok: false,
        status: "blocked",
        reason,
        autoReportWritten: true,
      };
    } catch (err) {
      return {
        ok: false,
        status: "failed",
        reason: err instanceof Error ? err.message : String(err),
      };
    }
  }

  return { ok: true, status: "done" };
}
