import { BadRequestException, Body, Controller, Get, Inject, Param, Post, Query, Request, UseGuards } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { ZodError } from 'zod';
import { FileService } from '../file/file.service';

import { AdminGuard } from 'src/jwt-auth/admin-auth.guard';
import { AuthGuard } from 'src/jwt-auth/auth.guard';
import { OptionalAuthGuard } from 'src/jwt-auth/optional-auth.guard';
import { User } from '../models/db.model';
import { JwtUser, Subscription, UserListingCriteria } from '../models/main.model';
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  constructor(
    private userService: UserService,
    private fileService: FileService,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  @UseGuards(OptionalAuthGuard)
  @Get()
  async findByMail(@Request() req, @Query('mail') mail: string): Promise<User> {
    const user = await this.userService.getUserByMail(mail, req.user as JwtUser);
    return user;
  }

  @UseGuards(OptionalAuthGuard)
  @Get(':id')
  async findById(@Param('id') id: string): Promise<User> {
    const user = await this.userService.getUserById(id);
    return user;
  }
  @UseGuards(AdminGuard)
  @Get('user/all')
  async getAllUser(): Promise<User[]> {
    return await this.userService.getAllUser();
  }

  @UseGuards(OptionalAuthGuard)
  @Post()
  async save(@Body() user: any): Promise<User> {
    try {
      const savedUser = await this.userService.saveUser(user);
      return savedUser;
    } catch (error) {
      if (error instanceof ZodError) {
        const filteredErrors = error.errors
          .map(item => ({
            ...item,
            field: item.path[0],
          }))
          .filter((item, index, self) => index === self.findIndex(t => t.path[0] === item.path[0]));
        throw new BadRequestException(filteredErrors);
      }
      throw error; // Andere Fehler einfach durchreichen
    }
  }

  @UseGuards(OptionalAuthGuard)
  @Post('guaranteed')
  async saveGuaranteed(@Body() user: any): Promise<User> {
    const savedUser = await this.userService.saveUser(user, false);
    return savedUser;
  }

  @UseGuards(OptionalAuthGuard)
  @Post('search')
  async find(@Body() criteria: UserListingCriteria): Promise<{ results: User[]; totalCount: number }> {
    const foundUsers = await this.userService.searchUserListings(criteria);
    return foundUsers;
  }

  @UseGuards(OptionalAuthGuard)
  @Post('findTotal')
  async findTotal(@Body() criteria: UserListingCriteria): Promise<number> {
    return await this.userService.getUserListingsCount(criteria);
  }

  @UseGuards(AuthGuard)
  @Get('subscriptions/:id')
  async findSubscriptionsById(@Param('id') id: string): Promise<Subscription[]> {
    const subscriptions = [];
    const user = await this.userService.getUserById(id);
    subscriptions.forEach(s => {
      s.userId = user.id;
      s.start = user.created;
      s.modified = user.created;
    });
    return subscriptions;
  }
}
