import {
  BadRequestException,
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  NotFoundException,
  Param,
  Patch,
  Post,
  Request,
} from '@nestjs/common';
import type { Request as ExpressRequest } from 'express';
import { RequirePermissions } from '@common/decorators/permissions.decorator';
import { PrismaService } from '@core/database/prisma/prisma.service';
import type { ModelRoutingScope } from '@prisma/client';
import { resolveOrgId, resolveActor } from '../utils/auth-resolution.util';

/**
 * PR10.6 follow-up: ModelRoutingRule admin CRUD endpoint。
 *
 * 之前 admin 页面只读，rule 编辑要走 SQL/seed；本批补 admin CRUD：
 * - GET    /agent/admin/rules               列规则（按 priority asc）
 * - POST   /agent/admin/rules               新建规则
 * - PATCH  /agent/admin/rules/:id           更新规则（部分字段）
 * - DELETE /agent/admin/rules/:id           删规则（硬删）
 *
 * 权限：system:admin（与 routing decisions dashboard 一致）。
 * 隔离：所有读写按 organizationId 过滤（resolveOrgId）。
 */

const VALID_SCOPES: ModelRoutingScope[] = ['ORGANIZATION', 'USER', 'PROJECT'];

interface CreateRuleBody {
  scope?: ModelRoutingScope;
  scopeRefId?: string;
  name?: string;
  priority?: number;
  enabled?: boolean;
  pattern?: unknown;
  primary?: { provider?: string; model?: string };
  fallbacks?: Array<{ provider: string; model: string }>;
  reasoning?: string;
}

interface UpdateRuleBody {
  name?: string;
  priority?: number;
  enabled?: boolean;
  pattern?: unknown;
  primary?: { provider?: string; model?: string };
  fallbacks?: Array<{ provider: string; model: string }>;
  reasoning?: string;
}

@Controller('agent/admin/rules')
export class AgentAdminRulesController {
  constructor(private readonly prisma: PrismaService) {}

  @Get()
  @RequirePermissions('system:admin')
  async list(@Request() req: ExpressRequest) {
    const orgId = resolveOrgId(req);
    if (!orgId) throw new BadRequestException('organizationId required');
    const items = await this.prisma.modelRoutingRule.findMany({
      where: { organizationId: orgId },
      orderBy: [{ priority: 'asc' }, { createdAt: 'desc' }],
      take: 200,
    });
    return { items };
  }

  @Post()
  @RequirePermissions('system:admin')
  async create(@Body() body: CreateRuleBody, @Request() req: ExpressRequest) {
    const { orgId, userId } = resolveActor(req);
    const scope = (body.scope ?? 'ORGANIZATION') as ModelRoutingScope;
    if (!VALID_SCOPES.includes(scope)) {
      throw new BadRequestException(`invalid scope; allowed: ${VALID_SCOPES.join(',')}`);
    }
    const scopeRefId = body.scopeRefId ?? orgId;
    const name = String(body.name ?? '').trim();
    if (!name) throw new BadRequestException('name required');
    if (!body.primary?.provider || !body.primary?.model) {
      throw new BadRequestException('primary.provider and primary.model required');
    }
    const created = await this.prisma.modelRoutingRule.create({
      data: {
        organizationId: orgId,
        scope,
        scopeRefId,
        name,
        priority: Number.isFinite(body.priority) ? Number(body.priority) : 500,
        enabled: body.enabled ?? true,
        pattern: (body.pattern ?? {}) as never,
        primary: body.primary as never,
        fallbacks: (body.fallbacks ?? []) as never,
        reasoning: body.reasoning ?? null,
        createdById: userId,
      },
    });
    return created;
  }

  @Patch(':id')
  @RequirePermissions('system:admin')
  async update(
    @Param('id') id: string,
    @Body() body: UpdateRuleBody,
    @Request() req: ExpressRequest,
  ) {
    const orgId = resolveOrgId(req);
    if (!orgId) throw new BadRequestException('organizationId required');
    const existing = await this.prisma.modelRoutingRule.findUnique({ where: { id } });
    if (!existing || existing.organizationId !== orgId) {
      throw new NotFoundException('rule not found');
    }
    const data: Record<string, unknown> = {};
    if (body.name !== undefined) data.name = String(body.name).trim();
    if (body.priority !== undefined) data.priority = Number(body.priority);
    if (body.enabled !== undefined) data.enabled = !!body.enabled;
    if (body.pattern !== undefined) data.pattern = body.pattern;
    if (body.primary !== undefined) data.primary = body.primary;
    if (body.fallbacks !== undefined) data.fallbacks = body.fallbacks;
    if (body.reasoning !== undefined) data.reasoning = body.reasoning;
    return this.prisma.modelRoutingRule.update({ where: { id }, data });
  }

  @Delete(':id')
  @RequirePermissions('system:admin')
  @HttpCode(200)
  async remove(@Param('id') id: string, @Request() req: ExpressRequest) {
    const orgId = resolveOrgId(req);
    if (!orgId) throw new BadRequestException('organizationId required');
    const existing = await this.prisma.modelRoutingRule.findUnique({ where: { id } });
    if (!existing || existing.organizationId !== orgId) {
      throw new NotFoundException('rule not found');
    }
    await this.prisma.modelRoutingRule.delete({ where: { id } });
    return { deleted: true, id };
  }
}
