import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { randomUUID } from 'node:crypto';
import { maskName } from '@pac/utils';
import { PrismaService } from '../../../prisma/prisma.service';
import { AiCallRunnerService } from '../ai-call-runner.service';
import { DraftRecallSummaryCall } from '../calls/draft-recall-summary/call';
import type { DraftRecallSummaryInput } from '../calls/draft-recall-summary/input.types';
import type { TenantScopeContext } from '../../../common/decorators/tenant-scope.decorator';

export interface RecallSummaryResult {
  /** 一句话摘要;status='empty' 时为 null */
  summary: string | null;
  status: 'ready' | 'empty';
  source?: 'agent' | 'template_fallback';
}

/**
 * RecallSummaryOrchestrator — 回访历史「一句话摘要」get-or-generate。
 *
 *   有 ready 的 plan_summaries[recall_history] → 直接返回(秒回,不调 LLM)。
 *   没有 → 取该 patient 的回访记录(plan_executions)→ 跑 AiCall → upsert 存库 → 返回。
 *   无回访记录 → status='empty'(前端继续展示结构数据,不显示摘要)。
 */
@Injectable()
export class RecallSummaryOrchestrator {
  private readonly logger = new Logger(RecallSummaryOrchestrator.name);
  private static readonly TYPE = 'recall_history' as const;

  constructor(
    private readonly prisma: PrismaService,
    private readonly runner: AiCallRunnerService,
    private readonly call: DraftRecallSummaryCall,
  ) {}

  async getOrGenerate(scope: TenantScopeContext, planId: string): Promise<RecallSummaryResult> {
    const plan = await this.prisma.followupPlan.findUnique({
      where: { id: planId },
      select: { id: true, hostId: true, tenantId: true, patientId: true },
    });
    if (!plan || plan.hostId !== scope.hostId || plan.tenantId !== scope.tenantId) {
      throw new NotFoundException(`Plan ${planId} not found`);
    }

    // 1) 已生成 → 直接返回
    const existing = await this.prisma.planSummary.findUnique({
      where: { planId_type: { planId: plan.id, type: RecallSummaryOrchestrator.TYPE } },
      select: { content: true, status: true, source: true },
    });
    if (existing?.status === 'ready' && existing.content) {
      return {
        summary: existing.content,
        status: 'ready',
        source: (existing.source as 'agent' | 'template_fallback' | null) ?? undefined,
      };
    }

    // 2) 取历史联系(诊所回访 patient_return_visits,patient 级,最近 12 条)
    const visits = await this.prisma.patientReturnVisit.findMany({
      where: { hostId: scope.hostId, tenantId: scope.tenantId, patientId: plan.patientId },
      orderBy: { taskDate: 'desc' },
      take: 12,
      select: {
        taskDate: true, type: true, status: true, taskStatus: true,
        treatmentItems: true, followContent: true, result: true,
      },
    });
    if (visits.length === 0) return { summary: null, status: 'empty' };

    const patient = await this.prisma.patient.findUnique({
      where: { id: plan.patientId },
      select: { name: true },
    });

    // ⭐ 未来排程判定放这里(程序算),不交给 LLM —— 回访表含未来排程,
    //   模型没有"今天"就分不清"还没到期"和"漏做了"(2026-07 生产事故)。
    //   口径:按**日期**比(taskDate 是 @db.Date,无时分秒),taskDate > today 即未到期。
    const today = new Date().toISOString().slice(0, 10);

    const input: DraftRecallSummaryInput = {
      patientNameMasked: maskName(patient?.name ?? null) ?? '该患者',
      today,
      items: visits.map((v) => {
        const taskDate = v.taskDate ? v.taskDate.toISOString().slice(0, 10) : null;
        return {
          taskDate,
          type: v.type,
          status: v.status,
          taskStatus: v.taskStatus,
          // 无日期 → 不算未来(宁可当普通历史,也不要给出"已排期"的错误暗示)
          isFuture: taskDate != null && taskDate > today,
          treatmentItems: v.treatmentItems,
          followContent: v.followContent,
          result: v.result,
        };
      }),
    };

    // 3) 跑 AiCall → upsert
    const result = await this.runner.run(this.call, input, {
      hostId: plan.hostId,
      tenantId: plan.tenantId,
      workflowRunId: randomUUID(),
      linkedPatientId: plan.patientId,
      linkedPlanId: plan.id,
      bustCache: false,
      evalMode: 'production',
    });

    await this.prisma.planSummary.upsert({
      where: { planId_type: { planId: plan.id, type: RecallSummaryOrchestrator.TYPE } },
      create: {
        hostId: plan.hostId,
        tenantId: plan.tenantId,
        planId: plan.id,
        type: RecallSummaryOrchestrator.TYPE,
        content: result.output.summary,
        status: 'ready',
        source: result.source,
        agentInvocationId: result.invocationId,
      },
      update: {
        content: result.output.summary,
        status: 'ready',
        source: result.source,
        agentInvocationId: result.invocationId,
      },
    });

    return { summary: result.output.summary, status: 'ready', source: result.source };
  }
}
