import { Injectable } from '@nestjs/common';
import { ExpensesService } from '../../expenses/expenses.service';
import type { AgentToolContext, ToolDef, ToolInputResult } from '../agent-tool.types';
import { optionalDate, optionalPositiveInt, optionalString, rejectUnknownKeys } from './tool-input';

interface Input { keyword?: string; periodStart?: string; periodEnd?: string; limit?: number }

@Injectable()
export class SearchExpensesTool implements ToolDef<Input> {
  readonly name = 'search_expenses';
  readonly skillKey = 'billing';
  readonly description = '查询费用记录（宿舍水电费/杂费和个人附加费），支持按宿舍号、学生姓名/学号和账期筛选。';
  readonly requiredPermission = 'expense:view';
  readonly inputSchema = {
    type: 'object',
    properties: {
      keyword: { type: 'string', maxLength: 100, description: '宿舍号或学生姓名/学号' },
      periodStart: { type: 'string', format: 'date' },
      periodEnd: { type: 'string', format: 'date' },
      limit: { type: 'integer', minimum: 1, maximum: 30 },
    },
    additionalProperties: false,
  };
  constructor(private readonly service: ExpensesService) {}

  validate(raw: Record<string, unknown>): ToolInputResult<Input> {
    const invalid = rejectUnknownKeys(raw, ['keyword', 'periodStart', 'periodEnd', 'limit']);
    if (invalid) return invalid;
    const keyword = optionalString(raw.keyword, 'keyword', 100); if (!keyword.ok) return keyword;
    const periodStart = optionalDate(raw.periodStart, 'periodStart');
    if (!periodStart.ok) return periodStart;
    const periodEnd = optionalDate(raw.periodEnd, 'periodEnd');
    if (!periodEnd.ok) return periodEnd;
    if (periodStart.value && periodEnd.value && periodStart.value > periodEnd.value) {
      return { ok: false, error: 'periodEnd 不能早于 periodStart' };
    }
    const limit = optionalPositiveInt(raw.limit, 'limit', 30); if (!limit.ok) return limit;
    return {
      ok: true,
      value: {
        keyword: keyword.value,
        periodStart: periodStart.value,
        periodEnd: periodEnd.value,
        limit: limit.value,
      },
    };
  }

  execute(input: Input, _context: AgentToolContext) {
    return this.service.agentSearchExpenses(input);
  }
}
