import { Controller, Get, Patch, Post, Delete, Body, Param, ParseIntPipe, BadRequestException } from '@nestjs/common';
import { IsBoolean, IsEmail, IsIn, IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
import { UsersService } from './users.service';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { Roles } from '../auth/decorators/roles.decorator';

class SetRoleDto {
  @IsIn(['admin', 'user'])
  role: string;
}

class SetPremiumDto {
  @IsBoolean()
  isPremium: boolean;
}

class SetRecipeSharingDto {
  @IsBoolean()
  canShareRecipes: boolean;
}

class AdminCreateUserDto {
  @IsString()
  @MinLength(2)
  @MaxLength(50)
  username: string;

  @IsEmail()
  email: string;

  @IsString()
  @MinLength(8)
  password: string;

  @IsOptional()
  @IsIn(['admin', 'user'])
  role?: string;
}

class UpdateEmailDto {
  @IsEmail()
  email: string;
}

class UpdateProfileDto {
  @IsOptional()
  @IsString()
  @MaxLength(100)
  firstName?: string;

  @IsOptional()
  @IsString()
  @MaxLength(100)
  lastName?: string;

  @IsOptional()
  @IsEmail()
  email?: string;
}

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get('me')
  async getMe(@CurrentUser() user: { userId: number; username: string }) {
    const found = await this.usersService.findById(user.userId);
    return {
      id: found?.id,
      username: found?.username,
      email: found?.email,
      firstName: found?.firstName,
      lastName: found?.lastName,
      role: found?.role,
    };
  }

  @Patch('me')
  async updateMe(
    @CurrentUser() user: { userId: number; username: string },
    @Body() dto: UpdateProfileDto,
  ) {
    const updated = await this.usersService.updateProfile(user.userId, dto);
    return {
      id: updated.id,
      username: updated.username,
      email: updated.email,
      firstName: updated.firstName,
      lastName: updated.lastName,
    };
  }

  @Roles('admin')
  @Get()
  listUsers() {
    return this.usersService.findAll();
  }

  @Roles('admin')
  @Patch(':id/role')
  async setRole(
    @Param('id', ParseIntPipe) id: number,
    @CurrentUser() caller: { userId: number; username: string; role: string },
    @Body() dto: SetRoleDto,
  ) {
    if (caller.userId === id) throw new BadRequestException('Du kan inte ändra din egen roll');
    const updated = await this.usersService.setRole(id, dto.role);
    return { id: updated.id, username: updated.username, role: updated.role };
  }

  @Roles('admin')
  @Patch(':id/premium')
  async setPremium(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: SetPremiumDto,
  ) {
    const updated = await this.usersService.setPremium(id, dto.isPremium);
    return { id: updated.id, username: updated.username, isPremium: updated.isPremium };
  }

  @Roles('admin')
  @Patch(':id/recipe-sharing')
  async setRecipeSharing(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: SetRecipeSharingDto,
  ) {
    const updated = await this.usersService.setRecipeSharing(id, dto.canShareRecipes);
    return { id: updated.id, username: updated.username, canShareRecipes: updated.canShareRecipes };
  }

  @Roles('admin')
  @Post()
  async adminCreateUser(
    @Body() dto: AdminCreateUserDto,
  ) {
    const user = await this.usersService.adminCreate(dto);
    return { id: user.id, username: user.username, email: user.email, role: user.role, createdAt: user.createdAt };
  }

  @Roles('admin')
  @Delete(':id')
  async deleteUser(
    @Param('id', ParseIntPipe) id: number,
    @CurrentUser() caller: { userId: number },
  ) {
    if (caller.userId === id) throw new BadRequestException('Du kan inte ta bort ditt eget konto');
    await this.usersService.deleteUser(id);
    return { deleted: true };
  }

  @Roles('admin')
  @Post(':id/reset-password')
  async resetPassword(
    @Param('id', ParseIntPipe) id: number,
    @CurrentUser() caller: { userId: number },
  ) {
    if (caller.userId === id) throw new BadRequestException('Du kan inte återställa ditt eget lösenord härifrån');
    const user = await this.usersService.findById(id);
    if (!user) throw new BadRequestException('Användaren hittades inte');
    const { temporaryPassword } = await this.usersService.resetPassword(id);
    const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? 'appen';
    const displayName = user.firstName ? user.firstName : user.username;
    return {
      to: user.email,
      subject: 'Ditt lösenord har återställts',
      body: `Hej ${displayName},\n\nDitt lösenord har återställts av en administratör.\nDitt nya tillôlliga lösenord är: ${temporaryPassword}\n\nLogga in på ${appUrl} och byt lösenord snarast.\n\nHälsningar`,
      temporaryPassword,
    };
  }

  @Roles('admin')
  @Patch(':id/email')
  async updateEmail(
    @Param('id', ParseIntPipe) id: number,
    @CurrentUser() caller: { userId: number },
    @Body() dto: UpdateEmailDto,
  ) {
    if (caller.userId === id) throw new BadRequestException('Använd "Min profil" för att ändra din egen e-post');
    const updated = await this.usersService.updateEmail(id, dto.email);
    return { id: updated.id, username: updated.username, email: updated.email };
  }
}
