import {
  ConflictException,
  Injectable,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateVehicleDto } from './dto/create-vehicle.dto';
import { UpdateVehicleDto } from './dto/update-vehicle.dto';
import { getPaginationOptions, formatPaginatedResponse } from 'src/common/lib/pagination-helper';
import { handlePrismaError } from 'src/common/lib/handlePrismaError';

@Injectable()
export class VehicleService {
  constructor(private prisma: PrismaService) { }

  async create(createVehicleDto: CreateVehicleDto, user?: any) {
    try {
      const vehicleExists = await this.prisma.vehicle.findUnique({
        where: { vehicleNumber: createVehicleDto.vehicleNumber },
      });

      if (vehicleExists) {
        throw new ConflictException('Vehicle with this number already exists');
      }
      let warehouseId = createVehicleDto.warehouseId;

      if (user.role !== 'ADMIN') {
        const getUser = await this.prisma.users.findUnique({
          where: { id: user.sub },
          select: { warehouseId: true },
        });

        if (!getUser?.warehouseId) {
          throw new NotFoundException('User warehouse not found');
        }

        warehouseId = getUser.warehouseId;
      }
      if (!warehouseId) {
        throw new BadRequestException('WarehouseId is required');
      }
      return await this.prisma.vehicle.create({
        data: {
          ...createVehicleDto,
          warehouseId,
        },
      });
    } catch (error) {
      handlePrismaError(error, 'Error creating vehicle');
    }
  }

  async findAll(page: number, perPage: number, query?: string, warehouseId?: string, user?: any,) {
    const { skip, take } = getPaginationOptions({ page, perPage });

    const where: any = {};

    if (query) {
      where.OR = [
        { vehicleNumber: { contains: query } },
        { tankNumber: { contains: query } },
        { cocNumber: { contains: query } },
      ];
    }

    if (warehouseId && warehouseId.trim() !== '') {
      where.warehouseId = warehouseId;
    } else if (user && user.role !== 'ADMIN') {
      const getUser = await this.prisma.users.findFirst({
        where: {
          id: user.sub
        }
      })
      where.warehouseId = getUser?.warehouseId;
    }

    const [items, total] = await this.prisma.$transaction([
      this.prisma.vehicle.findMany({
        where,
        skip,
        take,
        include: {
          warehouse: {
            select: {
              name: true
            }
          }
        }
      }),
      this.prisma.vehicle.count({ where }),
    ]);

    return formatPaginatedResponse(items, total, page, perPage);
  }

  async findOne(id: string) {
    const vehicle = await this.prisma.vehicle.findUnique({
      where: { id },
      include: {
        warehouse: {
          select: {
            name: true
          }
        }
      }
    });

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

    return vehicle;
  }

  async update(id: string, updateVehicleDto: UpdateVehicleDto, user?: any) {
    await this.findOne(id);
    try {
      if (updateVehicleDto.vehicleNumber) {
        const vehicleExists = await this.prisma.vehicle.findFirst({
          where: {
            vehicleNumber: updateVehicleDto.vehicleNumber,
            NOT: { id },
          },
        });

        if (vehicleExists) {
          throw new ConflictException('Vehicle with this number already exists');
        }
      }
      let warehouseId = updateVehicleDto.warehouseId;

      if (user?.role !== 'ADMIN') {
        const getUser = await this.prisma.users.findUnique({
          where: { id: user.sub },
          select: { warehouseId: true },
        });

        if (!getUser?.warehouseId) {
          throw new NotFoundException('User warehouse not found');
        }

        warehouseId = getUser.warehouseId;
      }
      return await this.prisma.vehicle.update({
        where: { id },
        data: { ...updateVehicleDto, warehouseId },
      });
    } catch (error) {
      handlePrismaError(error, 'Error updating vehicle');
    }
  }

  async remove(id: string) {
    await this.findOne(id);
    return this.prisma.vehicle.delete({
      where: { id },
    });
  }
}
