import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Put,
  Query,
  Request,
  UseGuards,
} from '@nestjs/common';
import { Throttle } from '@nestjs/throttler';
import { Public } from '../auth/decorators/public.decorator';
import { CreateProductDto } from './dto/create-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
import { ProductsService } from './products.service';
import { MergeProductsDto } from './dto/merge-products.dto';
import { UpdateCanonicalNameDto } from './dto/update-canonical-name.dto';
import { SetTagsDto } from './dto/set-tags.dto';
import { UpsertNutritionDto } from './dto/upsert-nutrition.dto';
import { BulkUpdateProductsDto } from './dto/bulk-update-products.dto';
import { AiCategorizeBulkDto } from './dto/ai-categorize-bulk.dto';
import { SetProductStatusDto } from './dto/set-product-status.dto';
import { Roles } from '../auth/decorators/roles.decorator';
import { AiService } from '../ai/ai.service';
import { CategoriesService } from '../categories/categories.service';
import { PremiumOrAdminGuard } from '../auth/premium-or-admin.guard';

@Controller('products')
export class ProductsController {
  constructor(
    private readonly productsService: ProductsService,
    private readonly aiService: AiService,
    private readonly categoriesService: CategoriesService,
  ) {}

  @Public()
  @Get()
  findAll(
    @Query('tag') tag?: string,
    @Query('subcategory') subcategory?: string,
  ) {
    return this.productsService.findAll({ tag, subcategory });
  }

  @Public()
  @Get('tags')
  findAllTags() {
    return this.productsService.findAllTags();
  }

  @Roles('admin')
  @Get('duplicates')
  findDuplicates() {
    return this.productsService.findDuplicateCandidates();
  }

  @Roles('admin')
  @Get('merge-preview')
  previewMerge(
    @Query('sourceProductId', ParseIntPipe) sourceProductId: number,
    @Query('targetProductId', ParseIntPipe) targetProductId: number,
  ) {
    return this.productsService.previewMerge(sourceProductId, targetProductId);
  }

  @Roles('admin')
  @Post('backfill-canonical')
  backfillCanonical() {
    return this.productsService.backfillCanonicalNames();
  }

  @Roles('admin')
  @Get('pending')
  findPending() {
    return this.productsService.findPending();
  }

  @Roles('admin')
  @Post('ai-categorize-bulk')
  @Throttle({ default: { ttl: 60_000, limit: 5 } })
  @HttpCode(200)
  aiCategorizeBulk(@Body() body: AiCategorizeBulkDto) {
    return this.productsService.aiCategorizeBulk(body.productIds);
  }

  @Roles('admin')
  @Get('deleted')
  findDeleted() {
    return this.productsService.findDeleted();
  }

  // Inloggad användares egna privata produkter (måste vara före :id)
  @Get('mine')
  findMine(@Request() req: { user: { id: number } }) {
    return this.productsService.findByOwner(req.user.id);
  }

  // Tillgänglig för alla inloggade användare
  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.productsService.findOne(id);
  }

  // Skapa en privat produkt för den inloggade användaren
  @Post('private')
  createPrivate(
    @Body() body: CreateProductDto,
    @Request() req: { user: { id: number } },
  ) {
    return this.productsService.createPrivate(body, req.user.id);
  }

  @UseGuards(PremiumOrAdminGuard)
  @Get(':id/suggest-category')
  @Throttle({ default: { ttl: 60_000, limit: 20 } })
  async suggestCategory(
    @Param('id', ParseIntPipe) id: number,
  ) {
    const product = await this.productsService.findOne(id);
    const categories = await this.categoriesService.findFlattened();
    return this.aiService.suggestCategory(product.canonicalName ?? product.name, categories);
  }

  @Roles('admin')
  @Post()
  create(@Body() body: CreateProductDto, @Request() req: { user: { id: number } }) {
    return this.productsService.create(body, req.user.id);
  }

  // Tillgänglig för alla inloggade användare — req.user.id injiceras av JWT-guard
  @Post('pending')
  createPending(
    @Body() body: CreateProductDto,
    @Request() req: { user: { id: number } },
  ) {
    return this.productsService.createPending(body, req.user.id);
  }

  @Roles('admin')
  @Post('merge')
  merge(@Body() body: MergeProductsDto) {
    return this.productsService.merge(body.sourceProductId, body.targetProductId);
  }

  @Roles('admin')
  @Patch(':id/canonical-name')
  updateCanonicalName(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: UpdateCanonicalNameDto,
  ) {
    return this.productsService.updateCanonicalName(id, body.canonicalName);
  }

  @Roles('admin')
  @Put(':id/tags')
  setTags(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: SetTagsDto,
  ) {
    return this.productsService.setTags(id, body.tags);
  }

  @Roles('admin')
  @Put(':id/nutrition')
  upsertNutrition(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: UpsertNutritionDto,
  ) {
    return this.productsService.upsertNutrition(id, body);
  }

  @Roles('admin')
  @Patch(':id')
  update(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: UpdateProductDto,
  ) {
    return this.productsService.update(id, body);
  }

  @Roles('admin')
  @Delete(':id/permanent')
  permanentDelete(@Param('id', ParseIntPipe) id: number) {
    return this.productsService.permanentDelete(id);
  }

  @Roles('admin')
  @Delete(':id')
  remove(@Param('id', ParseIntPipe) id: number) {
    return this.productsService.remove(id);
  }

  @Roles('admin')
  @Patch(':id/status')
  setStatus(
    @Param('id', ParseIntPipe) id: number,
    @Body() body: SetProductStatusDto,
  ) {
    return this.productsService.setStatus(id, body.status);
  }

  @Roles('admin')
  @Post(':id/restore')
  restore(@Param('id', ParseIntPipe) id: number) {
    return this.productsService.restore(id);
  }

  @Roles('admin')
  @Post('reset-all')
  @HttpCode(200)
  resetAll() {
    return this.productsService.resetAll();
  }

  @Roles('admin')
  @Post('bulk-update')
  @HttpCode(200)
  bulkUpdate(@Body() body: BulkUpdateProductsDto) {
    return this.productsService.bulkUpdate(body.ids, { categoryId: body.categoryId });
  }
}