/**
 * AgentPersona service —— 智能体 "你应该是谁"
 *
 * 系统预设：createdById=NULL；用户自创：createdById 非空（仅自己可见）。
 */

import { Injectable, ForbiddenException, BadRequestException } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { SkipAssertAccess } from '@common/decorators/skip-assert-access.decorator';
import type { AgentPersona } from '@prisma/client';
import { assertOwn } from '../utils/ownership.util';
import { assertNonEmptyString } from '../utils/validation.util';

/**
 * 系统预设清单。改这里 → 下一进程启动自动 sync 新条目。
 */
export const SYSTEM_PERSONAS: Array<{
  systemKey: string;
  name: string;
  icon: string;
  description: string;
  instructions: string;
}> = [
  {
    systemKey: 'general',
    name: '通用助手',
    icon: '✨',
    description: '默认通用助手，适合任何场景',
    instructions: '你是一位通用助手，对任何主题保持友好、准确、简洁。',
  },
  {
    systemKey: 'code-reviewer',
    name: '代码评审员',
    icon: '🧑‍💻',
    description: '聚焦代码质量、安全、可维护性',
    instructions:
      '你是一位资深代码评审员，重点关注：(1) 正确性 (2) 安全漏洞 (3) 可维护性 (4) 性能。' +
      '回复用 markdown 列表 + 行号引用。避免空泛的赞美。',
  },
  {
    systemKey: 'writer',
    name: '写作助手',
    icon: '✍️',
    description: '改写、润色、邮件、长文、PRD',
    instructions:
      '你是一位写作助手。回复时保持原作者口吻，只调整结构和措辞。' +
      '建议改动前先简述原因，并提供 2 个备选方案。',
  },
  {
    systemKey: 'data-analyst',
    name: '数据分析师',
    icon: '📊',
    description: 'SQL、报表、趋势分析、可视化建议',
    instructions:
      '你是数据分析师。涉及 SQL 时遵循 read-only + 显式 LIMIT；输出包含：' +
      '(1) 假设 (2) 查询 (3) 结果解读 (4) 后续问题。',
  },
  {
    systemKey: 'approver-helper',
    name: '审批助手',
    icon: '📋',
    description: '帮你写出差/采购/费用等审批申请',
    instructions:
      '你是审批申请助手，根据 FF AI Workspace 内部审批流程帮用户起草申请。' +
      '主动询问缺失字段（金额 / 时间 / 事由 / 对方），不臆造数字。',
  },
  {
    systemKey: 'knowledge-qa',
    name: '知识问答',
    icon: '📚',
    description: '查公司制度、流程、HR 政策',
    instructions:
      '你是公司知识库问答助手。先检索知识库，再回答；回答末尾必须列引用源（文档名 + 版本）。' +
      '没有引用源就说"我不确定，请联系相关部门"。',
  },
  {
    systemKey: 'translator',
    name: '翻译助手',
    icon: '🌐',
    description: '中英互译，保持术语一致',
    instructions:
      '你是翻译助手。默认中英互译；术语优先保留原文（如品牌名 / 项目代号 / 技术名词）。' +
      '提供两种风格：忠实 vs 本地化，让用户选。',
  },
];

const NAME_MAX = 120;

export interface CreatePersonaInput {
  organizationId: string;
  createdById: string;
  name: string;
  icon?: string;
  description?: string;
  instructions?: string;
  allowedTools?: string[];
}

export interface UpdatePersonaInput {
  name?: string;
  icon?: string;
  description?: string;
  instructions?: string;
  allowedTools?: string[];
  enabled?: boolean;
}

@Injectable()
export class AgentPersonasService {
  /** 本进程内已 seed 过的 org 集合，避免每次 list 重复打 DB */
  private readonly seededOrgs = new Set<string>();

  constructor(private readonly prisma: PrismaService) {}

  async list(organizationId: string, createdById: string): Promise<AgentPersona[]> {
    await this.ensureSystemSeeded(organizationId);
    return this.prisma.agentPersona.findMany({
      where: {
        organizationId,
        enabled: true,
        OR: [{ createdById: null }, { createdById }],
      },
      orderBy: [{ createdById: 'asc' }, { updatedAt: 'desc' }],
    });
  }

  async create(input: CreatePersonaInput): Promise<AgentPersona> {
    const name = assertNonEmptyString(input.name, 'name', NAME_MAX);
    return this.prisma.agentPersona.create({
      data: {
        organizationId: input.organizationId,
        createdById: input.createdById,
        systemKey: null,
        name,
        icon: input.icon ?? null,
        description: input.description ?? null,
        instructions: input.instructions ?? null,
        allowedTools: input.allowedTools ?? [],
      },
    });
  }

  async update(
    id: string,
    organizationId: string,
    createdById: string,
    patch: UpdatePersonaInput,
  ): Promise<AgentPersona> {
    const p = await this.assertEditable(id, organizationId, createdById);
    let name: string | undefined;
    if (patch.name !== undefined) {
      name = assertNonEmptyString(patch.name, 'name', NAME_MAX);
    }
    // 系统预设：只允许改 enabled / instructions / icon / description；不允许改 name / allowedTools
    if (p.systemKey) {
      const allowed: (keyof UpdatePersonaInput)[] = ['enabled', 'instructions', 'icon', 'description'];
      for (const key of Object.keys(patch) as (keyof UpdatePersonaInput)[]) {
        if (!allowed.includes(key)) {
          throw new ForbiddenException(`cannot modify '${key}' on system preset persona`);
        }
      }
    }
    return this.prisma.agentPersona.update({
      where: { id },
      data: {
        ...(name !== undefined ? { name } : {}),
        ...(patch.icon !== undefined ? { icon: patch.icon || null } : {}),
        ...(patch.description !== undefined ? { description: patch.description || null } : {}),
        ...(patch.instructions !== undefined ? { instructions: patch.instructions || null } : {}),
        ...(patch.allowedTools !== undefined ? { allowedTools: patch.allowedTools } : {}),
        ...(patch.enabled !== undefined ? { enabled: patch.enabled } : {}),
      },
    });
  }

  /** 用户自创 → 真删；系统预设 → 软隐藏（enabled=false），避免下次 seed 又恢复 */
  @SkipAssertAccess('入口即 assertEditable，写动作前已校验归属')
  async remove(id: string, organizationId: string, createdById: string): Promise<{ ok: true; soft: boolean }> {
    const p = await this.assertEditable(id, organizationId, createdById);
    if (p.systemKey) {
      await this.prisma.agentPersona.update({ where: { id }, data: { enabled: false } });
      return { ok: true, soft: true };
    }
    await this.prisma.agentPersona.delete({ where: { id } });
    return { ok: true, soft: false };
  }

  /**
   * 按 SYSTEM_PERSONAS 幂等 seed 当前 org（每进程每 org 仅一次）。
   * createMany skipDuplicates 单 RTT；不覆盖已有条目（用户改过的 enabled / 字段保留）。
   */
  private async ensureSystemSeeded(organizationId: string): Promise<void> {
    if (this.seededOrgs.has(organizationId)) return;
    await this.prisma.agentPersona.createMany({
      data: SYSTEM_PERSONAS.map((def) => ({
        organizationId,
        createdById: null,
        systemKey: def.systemKey,
        name: def.name,
        icon: def.icon,
        description: def.description,
        instructions: def.instructions,
        allowedTools: [],
        enabled: true,
      })),
      skipDuplicates: true,
    });
    this.seededOrgs.add(organizationId);
  }

  /**
   * 系统预设（createdById=null）任何 user 都能软隐藏；用户自创只允许 owner 改。
   */
  private async assertEditable(
    id: string,
    organizationId: string,
    createdById: string,
  ): Promise<AgentPersona> {
    const p = await this.prisma.agentPersona.findUnique({ where: { id } });
    return assertOwn(p, organizationId, createdById, { entityLabel: 'persona', allowSystemOwner: true });
  }
}
