import { Body, Controller, Get, Param, Post, Query, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiTags, ApiBearerAuth, ApiConsumes } from '@nestjs/swagger';
import { z } from 'zod';
import { DocumentIntakeSchema, DocumentIntakeBaseSchema, NlQuerySchema, RunAnalysisSchema, DraftDiscrepancyEmailSchema, AiProposalQuerySchema, DecideProposalSchema, PaginationQuery } from '@wms/shared';
import { RequirePermissions, RequireFeature } from '@/common/auth/decorators';
import { zodBody, zodQuery } from '@/common/validation/zod.pipe';
import { LlmService } from './llm/llm.service';
import { DocumentIntakeService } from './document-intake.service';
import { AnalyticsService } from './analytics.service';
import { CopilotService } from './copilot.service';
import { ProposalsService } from './proposals.service';

const ProposalQuery = AiProposalQuerySchema.merge(PaginationQuery);

/**
 * AI endpoints. Every write-capable outcome lands as a proposal; `decide` is
 * the only route that applies anything, and it needs the `ai.decide`
 * permission (supervisor and above by default).
 */
@ApiTags('ai')
@ApiBearerAuth()
@Controller('ai')
export class AiController {
  constructor(
    private readonly llm: LlmService,
    private readonly intake: DocumentIntakeService,
    private readonly analytics: AnalyticsService,
    private readonly copilot: CopilotService,
    private readonly proposals: ProposalsService,
  ) {}

  @Get('status') @RequirePermissions('ai.use') status() { return this.llm.status(); }

  // ---- document intake ----
  @Post('intake') @RequirePermissions('ai.use') @RequireFeature('ai.document_intake')
  intakeText(@Body(zodBody(DocumentIntakeSchema)) dto: z.infer<typeof DocumentIntakeSchema>) { return this.intake.intake(dto); }

  @Post('intake/upload') @RequirePermissions('ai.use') @RequireFeature('ai.document_intake') @UseInterceptors(FileInterceptor('file', { limits: { fileSize: 15 * 1024 * 1024 } })) @ApiConsumes('multipart/form-data')
  intakeFile(@Body() body: Record<string, string>, @UploadedFile() file: Express.Multer.File) {
    const dto = DocumentIntakeBaseSchema.parse({ ...body, text: body.text || undefined });
    return this.intake.intake(dto, file ? { buffer: file.buffer, originalname: file.originalname, mimetype: file.mimetype } : undefined);
  }

  @Post('discrepancy-email') @RequirePermissions('ai.use') @RequireFeature('ai.document_intake')
  discrepancyEmail(@Body(zodBody(DraftDiscrepancyEmailSchema)) dto: z.infer<typeof DraftDiscrepancyEmailSchema>) { return this.intake.draftDiscrepancyEmail(dto); }

  // ---- analytics (deterministic + narrative) ----
  @Post('analyses/run') @RequirePermissions('ai.use')
  runAnalysis(@Body(zodBody(RunAnalysisSchema)) dto: z.infer<typeof RunAnalysisSchema>) { return this.analytics.run(dto); }

  // ---- copilot ----
  @Post('copilot/ask') @RequirePermissions('ai.use') @RequireFeature('ai.nl_query')
  ask(@Body(zodBody(NlQuerySchema)) dto: z.infer<typeof NlQuerySchema>) { return this.copilot.ask(dto); }
  @Get('copilot/conversations') @RequirePermissions('ai.use') conversations() { return this.copilot.listConversations(); }
  @Get('copilot/conversations/:id') @RequirePermissions('ai.use') conversation(@Param('id') id: string) { return this.copilot.conversation(id); }

  // ---- proposals ----
  @Get('proposals') @RequirePermissions('ai.use') list(@Query(zodQuery(ProposalQuery)) q: z.infer<typeof ProposalQuery>) { return this.proposals.list(q); }
  @Get('proposals/inbox') @RequirePermissions('ai.use') inbox(@Query('warehouseId') warehouseId?: string) { return this.proposals.inbox(warehouseId); }
  @Get('proposals/:id') @RequirePermissions('ai.use') get(@Param('id') id: string) { return this.proposals.get(id); }
  @Post('proposals/:id/decide') @RequirePermissions('ai.decide')
  decide(@Param('id') id: string, @Body(zodBody(DecideProposalSchema)) dto: z.infer<typeof DecideProposalSchema>) { return this.proposals.decide(id, dto); }
}
