import { NextResponse } from "next/server";
import { z } from "zod";

import { requireApiAccess } from "../../../../../lib/api/auth";
import {
  HUMAN_COPY_RUBRIC_V1,
  scoreHumanCopyResult,
} from "../../../../../lib/calibration/scoring";
import type {
  ArticleCaseInputPayload,
  OptimizationCaseDetail,
  ProcessSummaryStep,
} from "../../../../../lib/cases/types";
import { createProcessStep, excerpt } from "../../../../../lib/cases/summaries";
import {
  getRepositoryFromRuntime,
  type AppRepository,
} from "../../../../../lib/db/repository";
import {
  articleInputSchema,
  copyOptimizationRequestSchema,
  optimizationFactCardSchema,
} from "../../../../../lib/domain/validation";
import type { LlmAuditSummary } from "../../../../../lib/llm/audit";
import { LlmValidationError } from "../../../../../lib/llm/client";
import { getExportStoreFromRuntime } from "../../../../../lib/workflow/export-store";
import { extractCandidateFactCard } from "../../../../../lib/workflow/fact-extractor";
import { runOptimizationWorkflow } from "../../../../../lib/workflow/orchestrator";
import { optimizeRenweiCopy } from "../../../../../lib/workflow/renwei-copy-optimizer";

interface RouteContext {
  params: Promise<{ caseId: string }>;
}

export async function POST(request: Request, context: RouteContext) {
  const access = requireApiAccess(request);
  if (!access.ok) {
    return access.response;
  }

  const { caseId } = await context.params;
  const repository = getRepositoryFromRuntime();
  const detail = await repository.getOptimizationCaseDetail(caseId);
  if (!detail?.input) {
    return NextResponse.json({ error: "Case not found" }, { status: 404 });
  }
  const caseDetail = { ...detail, input: detail.input } satisfies CaseDetailWithInput;

  if (detail.case.case_type === "article") {
    return rerunArticleCase(repository, caseDetail);
  }

  if (detail.case.case_type === "human_copy") {
    return rerunHumanCopyCase(repository, caseDetail);
  }

  return NextResponse.json({ error: "Unsupported case type" }, { status: 400 });
}

type CaseDetailWithInput = OptimizationCaseDetail & {
  input: NonNullable<OptimizationCaseDetail["input"]>;
};

async function rerunHumanCopyCase(
  repository: AppRepository,
  detail: CaseDetailWithInput,
) {
  const payload = copyOptimizationRequestSchema.parse(detail.input.payload);
  const startedAt = Date.now();
  const llmAuditSummary: LlmAuditSummary[] = [];

  try {
    const result = await optimizeRenweiCopy(payload, {
      onAuditSummary: (summary) => {
        llmAuditSummary.push(summary);
      },
    });
    const resultVersion = await repository.createOptimizationResultVersion({
      case_id: detail.case.id,
      case_type: "human_copy",
      status: "optimized",
      article_job_id: null,
      article_revision: null,
      result_summary: excerpt(result.optimized_text),
      payload: result,
      process_summary: [
        createProcessStep({
          stage: "human_copy_optimize",
          startedAt,
          endedAt: Date.now(),
          status: "success",
          producedResultVersion: true,
        }),
      ],
      llm_audit_summary: llmAuditSummary,
      error_stage: null,
      error_summary: null,
    });
    await repository.saveRubricVersion(HUMAN_COPY_RUBRIC_V1);
    await repository.saveScoringRun(
      scoreHumanCopyResult({
        resultVersionId: resultVersion.id,
        result,
      }),
    );

    return NextResponse.json(
      {
        case: { id: detail.case.id, case_type: "human_copy" },
        result_version: { id: resultVersion.id, version: resultVersion.version },
        result,
      },
      { status: 201 },
    );
  } catch (error) {
    const message = errorMessage(error);
    const resultVersion = await repository.createOptimizationResultVersion({
      case_id: detail.case.id,
      case_type: "human_copy",
      status: "failed",
      article_job_id: null,
      article_revision: null,
      result_summary: "",
      payload: null,
      process_summary: [
        createProcessStep({
          stage: "human_copy_optimize",
          startedAt,
          endedAt: Date.now(),
          status: "failed",
          errorSummary: message,
          producedResultVersion: false,
        }),
      ],
      llm_audit_summary: llmAuditSummary,
      error_stage: "human_copy_optimize",
      error_summary: message,
    });

    return NextResponse.json(
      {
        error: message,
        case: { id: detail.case.id, case_type: "human_copy" },
        result_version: { id: resultVersion.id, version: resultVersion.version },
      },
      { status: getErrorStatus(error) },
    );
  }
}

function errorMessage(error: unknown) {
  return error instanceof z.ZodError
    ? "请输入需要优化的文案"
    : error instanceof Error
      ? error.message
      : "文案优化失败";
}

function getErrorStatus(error: unknown) {
  if (error instanceof LlmValidationError) return 502;
  if (error instanceof Error && /^LLM\b|provider/i.test(error.message)) return 502;
  return 400;
}

async function rerunArticleCase(
  repository: AppRepository,
  detail: CaseDetailWithInput,
) {
  const payload = detail.input.payload as ArticleCaseInputPayload;
  const articleInput = articleInputSchema.parse({
    title: payload.source_title,
    body: payload.source_body,
    images: payload.image_inputs,
    platform: payload.publish_platform,
    user_instructions: payload.user_instructions,
  });
  const llmAuditSummary: LlmAuditSummary[] = [];
  const processSummary: ProcessSummaryStep[] = [];
  const requestStartedAt = Date.now();
  let jobId: string | null = null;
  let stage = "job";

  try {
    const job = await repository.createArticleJob({
      case_id: detail.case.id,
      source_title: articleInput.title,
      source_body: articleInput.body,
      image_inputs: articleInput.images,
      publish_platform: articleInput.platform,
      user_instructions: articleInput.user_instructions,
    });
    jobId = job.id;

    stage = "fact_card";
    const factCardStartedAt = Date.now();
    const existingFactCard = detail.input.article_job_id
      ? await repository.getFactCard(detail.input.article_job_id)
      : null;
    const factCard = optimizationFactCardSchema.parse(
      payload.fact_card ??
        existingFactCard ??
        (await extractCandidateFactCard(articleInput, {
          onAuditSummary: (summary) => {
            llmAuditSummary.push(summary);
          },
        })),
    );
    processSummary.push(
      createProcessStep({
        stage: "fact_card",
        startedAt: factCardStartedAt,
        endedAt: Date.now(),
        status: "success",
        producedResultVersion: false,
      }),
    );
    const savedFactCard = await repository.saveFactCard(job.id, factCard);

    stage = "optimize";
    const result = await runOptimizationWorkflow({
      input: articleInput,
      factCard: savedFactCard,
      onAuditSummary: (summary) => {
        llmAuditSummary.push(summary);
      },
    });
    const optimizedArticle = await repository.saveOptimizedArticle(
      job.id,
      result.article,
    );
    const qaReport = await repository.saveQaReport(
      job.id,
      optimizedArticle.revision ?? 1,
      result.qaReport,
    );
    const exportStore = getExportStoreFromRuntime();
    const exportPaths = await exportStore.writeJobExports({
      jobId: job.id,
      article: optimizedArticle,
      qaReport,
    });
    await repository.updateArticleJob(job.id, {
      status: "optimized",
      export_paths: exportPaths,
    });
    const resultVersion = await repository.createOptimizationResultVersion({
      case_id: detail.case.id,
      case_type: "article",
      status: "optimized",
      article_job_id: job.id,
      article_revision: optimizedArticle.revision ?? 1,
      result_summary: optimizedArticle.summary,
      payload: {
        article: optimizedArticle,
        qa_report: qaReport,
        export_paths: exportPaths,
      },
      process_summary: processSummary,
      llm_audit_summary: llmAuditSummary,
      error_stage: null,
      error_summary: null,
    });

    return NextResponse.json(
      {
        case: { id: detail.case.id, case_type: "article" },
        result_version: { id: resultVersion.id, version: resultVersion.version },
        optimizedArticle,
        qaReport,
        exportPaths,
        rewriteRounds: result.rewrite_rounds,
        stoppedAfterMaxRewrites: result.stopped_after_max_rewrites,
        timing: result.timing,
      },
      { status: 201 },
    );
  } catch (error) {
    const message = error instanceof Error ? error.message : "文章优化失败";
    const resultVersion = await repository.createOptimizationResultVersion({
      case_id: detail.case.id,
      case_type: "article",
      status: "failed",
      article_job_id: jobId,
      article_revision: null,
      result_summary: "",
      payload: null,
      process_summary: [
        ...processSummary,
        createProcessStep({
          stage,
          startedAt: requestStartedAt,
          endedAt: Date.now(),
          status: "failed",
          errorSummary: message,
          producedResultVersion: false,
        }),
      ],
      llm_audit_summary: llmAuditSummary,
      error_stage: stage,
      error_summary: message,
    });
    if (jobId) {
      await repository.updateArticleJob(jobId, { status: "failed" });
    }

    return NextResponse.json(
      {
        error: message,
        case: { id: detail.case.id, case_type: "article" },
        result_version: { id: resultVersion.id, version: resultVersion.version },
      },
      { status: getErrorStatus(error) },
    );
  }
}
