import { Injectable, NotFoundException, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { UpdateUserDto, ApproveUserDto } from './dto';
import { Role } from '@prisma/client';

@Injectable()
export class UsersService {
  private readonly logger = new Logger(UsersService.name);

  constructor(private prisma: PrismaService) {}

  async findAll() {
    return this.prisma.user.findMany({
      where: { deletedAt: null },
      include: { driver: true },
      orderBy: { createdAt: 'desc' },
    });
  }

  async findOne(id: string) {
    const user = await this.prisma.user.findFirst({
      where: { id, deletedAt: null },
      include: { driver: true },
    });

    if (!user) {
      throw new NotFoundException(`User with ID ${id} not found`);
    }

    return user;
  }

  async update(id: string, updateUserDto: UpdateUserDto) {
    const user = await this.findOne(id);

    this.logger.log(`Updating user ${id}: ${JSON.stringify(updateUserDto)}`);

    const { isAlsoDriver, ...prismaData } = updateUserDto;
    const effectiveRole = updateUserDto.role || user.role;

    const hasActiveDriver = user.driver && !user.driver.deletedAt;
    const hasSoftDeletedDriver = user.driver && user.driver.deletedAt;

    // Handle role change to DRIVER: auto-create or restore driver record
    if (updateUserDto.role === Role.DRIVER && !hasActiveDriver) {
      if (hasSoftDeletedDriver) {
        this.logger.log(
          `Restoring soft-deleted Driver record for user ${user.email} (role change to DRIVER)`,
        );
        await this.prisma.driver.update({
          where: { id: user.driver!.id },
          data: { deletedAt: null, name: user.name || user.email },
        });
      } else {
        this.logger.log(
          `Creating Driver record for user ${user.email} (role change to DRIVER)`,
        );
        await this.prisma.driver.create({
          data: {
            name: user.name || user.email,
            phone: user.email,
            userId: user.id,
          },
        });
      }
    }

    // When promoting FROM DRIVER to Admin/Coordinator, keep the driver record
    // (admin can explicitly uncheck the driver box later if they want)

    // Handle "Also a Driver" toggle (independent of role)
    if (isAlsoDriver === true && !hasActiveDriver) {
      if (hasSoftDeletedDriver) {
        this.logger.log(
          `Restoring soft-deleted Driver record for user ${user.email} (isAlsoDriver toggled on)`,
        );
        await this.prisma.driver.update({
          where: { id: user.driver!.id },
          data: { deletedAt: null, name: user.name || user.email },
        });
      } else {
        this.logger.log(
          `Creating Driver record for user ${user.email} (isAlsoDriver toggled on)`,
        );
        await this.prisma.driver.create({
          data: {
            name: user.name || user.email,
            phone: user.email,
            userId: user.id,
          },
        });
      }
    } else if (isAlsoDriver === false && hasActiveDriver && effectiveRole !== Role.DRIVER) {
      // Only allow removing driver record if user is NOT in the DRIVER role
      this.logger.log(
        `Soft-deleting Driver record for user ${user.email} (isAlsoDriver toggled off)`,
      );
      await this.prisma.driver.update({
        where: { id: user.driver!.id },
        data: { deletedAt: new Date() },
      });
    }

    return this.prisma.user.update({
      where: { id: user.id },
      data: prismaData,
      include: { driver: true },
    });
  }

  async approve(id: string, approveUserDto: ApproveUserDto) {
    const user = await this.findOne(id);

    this.logger.log(
      `${approveUserDto.isApproved ? 'Approving' : 'Denying'} user: ${user.email}`,
    );

    return this.prisma.user.update({
      where: { id: user.id },
      data: { isApproved: approveUserDto.isApproved },
      include: { driver: true },
    });
  }

  async remove(id: string) {
    const user = await this.findOne(id);

    this.logger.log(`Soft deleting user: ${user.email}`);

    return this.prisma.user.update({
      where: { id: user.id },
      data: { deletedAt: new Date() },
    });
  }

  async getPendingUsers() {
    return this.prisma.user.findMany({
      where: {
        deletedAt: null,
        isApproved: false,
      },
      orderBy: { createdAt: 'asc' },
    });
  }
}
