import type { Logger } from "pino";
import type { JiraClientImpl } from "@/jira/client.js";
import type { FixPipeline } from "@/pipeline/fix-pipeline.js";
import type { SlackNotifier } from "@/slack/client.js";
import type { JiraTicketReviewJobPayload, PipelineResult, TriageVerdict } from "@/types/index.js";
import { markTicketReviewTriggerProcessed } from "@/poller/ticket-review-processed.js";
import { formatReadinessVerdictForHumans } from "@/utils/readiness-display.js";

const JIRA_COMMENT_MAX = 30_000;

interface ReviewTicketPipelineDeps {
  jiraClient: JiraClientImpl;
  fixPipeline: FixPipeline;
  jiraDomain: string;
  slackNotifier?: SlackNotifier;
  /** Same as {@link FixPipeline} — for `pendingJobs` on pipeline start logs (Datadog). */
  getPendingCount?: () => number;
  logger: Logger;
}

function jiraBrowseUrl(domain: string, issueKey: string): string {
  return `https://${domain}.atlassian.net/browse/${issueKey}`;
}

/** Exported for unit tests (optional `maxCommentChars` forces truncation footer). */
export function formatReviewJiraComment(
  verdict: TriageVerdict,
  summary: string,
  questions: string | null,
  maxCommentChars: number = JIRA_COMMENT_MAX,
): string {
  const parts = [
    "Implementation readiness (hu-developer-bot)",
    "",
    `Verdict: ${formatReadinessVerdictForHumans(verdict)}`,
    "",
    "Summary:",
    summary.slice(0, 12_000),
  ];
  if (questions) {
    parts.push("", "Questions / gaps:", questions.slice(0, 8_000));
  }
  let text = parts.join("\n\n");
  if (text.length > maxCommentChars) {
    const footer = "\n\n_(Remainder truncated for Jira comment size limit.)_";
    const budget = maxCommentChars - footer.length;
    text = `${text.slice(0, Math.max(0, budget))}${footer}`;
  }
  return text;
}

export class ReviewTicketPipeline {
  constructor(private readonly deps: ReviewTicketPipelineDeps) {}

  async execute(job: JiraTicketReviewJobPayload, _signal?: AbortSignal): Promise<PipelineResult> {
    const { logger } = this.deps;
    const issueKey = job.issueKey;
    const jiraUrl = jiraBrowseUrl(this.deps.jiraDomain, issueKey);
    const log = logger.child({
      issueKey,
      jobKey: issueKey,
      jobKind: "jira_ticket_review",
    });

    log.info(
      {
        pendingJobs: this.deps.getPendingCount?.(),
      },
      "ticket_review_pipeline_started",
    );

    if (this.deps.slackNotifier) {
      try {
        await this.deps.slackNotifier.notifyTicketReviewStarted(issueKey, job.summary, jiraUrl);
      } catch (err) {
        log.warn(
          { err: err instanceof Error ? err.message : String(err) },
          "slack_ticket_review_start_failed",
        );
      }
    }

    try {
      const result = await this.deps.fixPipeline.evaluateCardReadiness(issueKey);

      const jiraBody = formatReviewJiraComment(result.verdict, result.summary, result.questions);

      await this.deps.jiraClient.addComment(issueKey, jiraBody);
      log.info("ticket_review_jira_comment_posted");

      if (this.deps.slackNotifier) {
        try {
          await this.deps.slackNotifier.notifyTicketReviewFinished(
            issueKey,
            jiraUrl,
            result.verdict,
            result.summary,
          );
        } catch (err) {
          log.warn(
            { err: err instanceof Error ? err.message : String(err) },
            "slack_ticket_review_finish_failed",
          );
        }
      }

      markTicketReviewTriggerProcessed(issueKey, job.triggeredByCommentId);

      const outcome: PipelineResult["outcome"] =
        result.verdict === "NEEDS_INFO"
          ? "needs_info"
          : result.verdict === "RUN_FAILED"
            ? "run_failed" // RUN_FAILED — CLI/readiness run did not succeed; distinct from thrown errors
            : "completed";

      log.info(
        {
          verdict: result.verdict,
          outcome,
          success: result.verdict !== "RUN_FAILED",
        },
        "ticket_review_pipeline_finished",
      );

      return {
        success: result.verdict !== "RUN_FAILED",
        issueKey,
        outcome,
        abortReason: result.verdict === "RUN_FAILED" ? result.summary : undefined,
      };
    } catch (err) {
      const message = err instanceof Error ? err.message : String(err);
      log.error({ err: message }, "ticket_review_pipeline_failed");

      const failComment = [
        "Implementation readiness failed (hu-developer-bot)",
        "",
        message.slice(0, 8_000),
      ].join("\n\n");

      try {
        await this.deps.jiraClient.addComment(issueKey, failComment);
      } catch (commentErr) {
        log.error(
          { err: commentErr instanceof Error ? commentErr.message : String(commentErr) },
          "ticket_review_failure_comment_failed",
        );
      }

      if (this.deps.slackNotifier) {
        try {
          await this.deps.slackNotifier.notifyTicketReviewFailed(issueKey, jiraUrl, message);
        } catch (slackErr) {
          log.warn(
            { err: slackErr instanceof Error ? slackErr.message : String(slackErr) },
            "slack_ticket_review_failed_notify_failed",
          );
        }
      }

      markTicketReviewTriggerProcessed(issueKey, job.triggeredByCommentId);

      return {
        success: false,
        issueKey,
        outcome: "completed",
        abortReason: message,
      };
    }
  }
}
