import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { Organization } from '../../entities/organization.entity';
import { StudentsService } from '../../students/students.service';
import type { AgentToolContext, ToolDef, ToolInputResult } from '../agent-tool.types';

/** Whitelisted input shape for create_student. */
interface CreateStudentInput {
  name: string;
  phone?: string;
  gender?: 'male' | 'female' | '男' | '女';
  studentNo?: string;
  idNumber?: string;
  organizationId?: number;
}

/** Forbidden input keys — if the model sends these, validation fails. */
const FORBIDDEN_INPUT_KEYS = new Set([
  'userId',
  'isSuperAdmin',
  'permissions',
  'roles',
  'ability',
  'user',
  'password',
  'token',
]);

const PHONE_RE = /^1[3-9]\d{9}$/;

/**
 * Creates a student archive from form-confirmed data.
 *
 * This is a write tool. It is only exposed to the model after the user
 * submits a rendered form (see AiChatService), and the executor still
 * enforces `student:create` at execution time.
 */
@Injectable()
export class CreateStudentTool implements ToolDef<CreateStudentInput> {
  readonly name = 'create_student';
  readonly skillKey = 'student';
  readonly inputSchema = {
    type: 'object',
    properties: {
      name: { type: 'string', description: '学生姓名', maxLength: 50 },
      phone: { type: 'string', description: '11 位手机号', pattern: '^1[3-9]\\d{9}$' },
      gender: {
        type: 'string',
        description: '性别',
        enum: ['male', 'female', '男', '女'],
      },
      studentNo: { type: 'string', description: '学号（选填）', maxLength: 30 },
      idNumber: { type: 'string', description: '身份证号（选填）', maxLength: 30 },
      organizationId: { type: 'integer', description: '校区ID（选填，缺省用主校区）', minimum: 1 },
    },
    additionalProperties: false,
  };
  readonly description =
    '根据用户通过表单提交的学生信息创建学生档案。仅可在表单提交后的轮次使用，不得自行编造或修改字段。';
  readonly requiredPermission = 'student:create';

  constructor(
    private readonly studentsService: StudentsService,
    private readonly dataSource: DataSource,
  ) {}

  validate(input: Record<string, unknown>): ToolInputResult<CreateStudentInput> {
    for (const key of Object.keys(input)) {
      if (FORBIDDEN_INPUT_KEYS.has(key)) {
        return { ok: false, error: `不允许的输入字段: ${key}` };
      }
    }

    const allowedKeys = new Set([
      'name',
      'phone',
      'gender',
      'studentNo',
      'idNumber',
      'organizationId',
    ]);
    for (const key of Object.keys(input)) {
      if (!allowedKeys.has(key)) {
        return { ok: false, error: `不允许的输入字段: ${key}` };
      }
    }

    if (typeof input.name !== 'string' || !input.name.trim() || input.name.trim().length > 50) {
      return { ok: false, error: 'name 必须是 1-50 个字符的字符串' };
    }

    const result: CreateStudentInput = { name: input.name.trim() };

    if (input.phone !== undefined) {
      if (typeof input.phone !== 'string' || !PHONE_RE.test(input.phone)) {
        return { ok: false, error: 'phone 必须是 11 位手机号' };
      }
      result.phone = input.phone;
    }

    if (input.gender !== undefined) {
      if (!['male', 'female', '男', '女'].includes(String(input.gender))) {
        return { ok: false, error: 'gender 只能是 male/female/男/女' };
      }
      result.gender = input.gender as CreateStudentInput['gender'];
    }

    if (input.studentNo !== undefined) {
      if (typeof input.studentNo !== 'string' || input.studentNo.length > 30) {
        return { ok: false, error: 'studentNo 必须是长度不超过 30 的字符串' };
      }
      result.studentNo = input.studentNo;
    }

    if (input.idNumber !== undefined) {
      if (typeof input.idNumber !== 'string' || input.idNumber.length > 30) {
        return { ok: false, error: 'idNumber 必须是长度不超过 30 的字符串' };
      }
      result.idNumber = input.idNumber;
    }

    if (input.organizationId !== undefined) {
      const id = Number(input.organizationId);
      if (!Number.isInteger(id) || id <= 0) {
        return { ok: false, error: 'organizationId 必须是正整数' };
      }
      result.organizationId = id;
    }

    return { ok: true, value: result };
  }

  async execute(input: CreateStudentInput, _context: AgentToolContext): Promise<unknown> {
    const organizationId = input.organizationId ?? (await this.resolveDefaultOrganizationId());
    const created = await this.studentsService.create({
      name: input.name,
      phone: input.phone,
      gender: input.gender,
      studentNo: input.studentNo,
      idNumber: input.idNumber,
      organizationId,
    });
    return {
      id: created.id,
      name: created.name,
      studentNo: created.studentNo ?? null,
      message: '学生已创建',
    };
  }

  private async resolveDefaultOrganizationId(): Promise<number> {
    const repo = this.dataSource.getRepository(Organization);
    const host = await repo.findOne({
      where: { isHost: true, status: 'active' },
      order: { id: 'ASC' },
    });
    const organization =
      host ??
      (await repo.findOne({
        where: { status: 'active' },
        order: { id: 'ASC' },
      }));
    if (!organization) throw new Error('未找到可用校区，无法创建学生');
    return organization.id;
  }
}
