import { BadRequestException, Injectable } from '@nestjs/common';
import { CreateWarehouseDto } from './dto/create-warehouse.dto';
import { UpdateWarehouseDto } from './dto/update-warehouse.dto';
import { PrismaService } from 'src/prisma/prisma.service';
import { handlePrismaError } from 'src/common/lib/handlePrismaError';
import { warehouseSelect } from 'src/selects/warehouse';
import { formatPaginatedResponse, getPaginationOptions } from 'src/common/lib/pagination-helper';
import { MoveCylindersDto } from './dto/move-cylinders.dto';
import { CylinderMovement } from '@prisma/client';

@Injectable()
export class WarehouseService {
  constructor(private readonly prisma: PrismaService) { }
  async create(createWarehouseDto: CreateWarehouseDto) {
    if (createWarehouseDto.capacity <= 0) {
      throw new BadRequestException("Capacity must be a positive number");
    }
    try {

      if (createWarehouseDto.readerId) {
        await this.prisma.reader.update({
          where: { id: createWarehouseDto.readerId },
          data: { status: true },
        });
      }

      const warehouse = await this.prisma.warehouse.create({
        data: createWarehouseDto,
        select: warehouseSelect,
      });

      return warehouse;
    } catch (error) {
      throw handlePrismaError(error);
    }
  }

  async findAll(page: number, perPage: number, search?: string) {
    try {
      const { skip, take } = getPaginationOptions({ page, perPage });

      const where: any = {};

      if (search) {
        search = search.trim();
        where.OR = [
          { name: { contains: search } },
          { location: { contains: search } },
          { managerName: { contains: search } },
        ];
      }

      const [items, total] = await this.prisma.$transaction([
        this.prisma.warehouse.findMany({
          where,
          select: warehouseSelect,
          skip,
          take,
          orderBy: { createdAt: "desc" },
        }),
        this.prisma.warehouse.count({ where }),
      ]);

      const warehouseIds = items.map((w) => w.id);

      const grouped = warehouseIds.length
        ? await this.prisma.cylinders.groupBy({
            by: ['warehouseId', 'status'],
            where: { warehouseId: { in: warehouseIds } },
            _count: { _all: true },
          })
        : [];

      const itemsWithCounts = items.map((w) => {
        const rows = grouped.filter((g) => g.warehouseId === w.id);
        const countOf = (status: string) =>
          rows.find((r) => r.status === status)?._count._all || 0;

        const inside = countOf('INSIDE') + countOf('ASSIGNED');
        const outside = countOf('OUTSIDE');
        const totalCylinders = rows.reduce((sum, r) => sum + r._count._all, 0);

        return {
          ...w,
          cylinderCounts: { total: totalCylinders, inside, outside },
        };
      });

      return formatPaginatedResponse(itemsWithCounts, total, page, perPage);
    } catch (error) {
      console.log('error===========', error);

      handlePrismaError(error, "Fetching paginated Warehouses");
    }
  }

  async findDistinctNames(page: number, perPage: number) {
    try {
      const { skip, take } = getPaginationOptions({ page, perPage });

      const total = (
        await this.prisma.warehouse.groupBy({
          by: ['name'],
        })
      ).length;

      const items = await this.prisma.warehouse.groupBy({
        by: ['name'],
        _min: {
          id: true,
        },
        skip,
        take,
        orderBy: {
          name: 'asc',
        },
      });

      const formattedItems = items.map(item => ({
        id: item._min.id,
        name: item.name,
      }));

      return formatPaginatedResponse(
        formattedItems,
        total,
        page,
        perPage
      );
    } catch (error) {
      handlePrismaError(error, 'Fetching distinct warehouse names');
    }
  }


  async findOne(id: string) {
    try {
      const warehouse = await this.prisma.warehouse.findUniqueOrThrow({
        where: { id },
        select: warehouseSelect,
      });
      return warehouse;
    } catch (error) {
      throw handlePrismaError(error);
    }
  }

  async update(id: string, updateWarehouseDto: UpdateWarehouseDto) {
    if (updateWarehouseDto.capacity && updateWarehouseDto.capacity <= 0) {
      throw new BadRequestException('Capacity must be a positive number');
    }
    try {
      const existingWarehouse = await this.prisma.warehouse.findUnique({
        where: { id },
      });

      if (updateWarehouseDto.readerId !== undefined) {
        if (existingWarehouse?.readerId && existingWarehouse.readerId !== updateWarehouseDto.readerId) {
          await this.prisma.reader.update({
            where: { id: existingWarehouse.readerId },
            data: { status: false },
          });
        }

        if (updateWarehouseDto.readerId) {
          await this.prisma.reader.update({
            where: { id: updateWarehouseDto.readerId },
            data: { status: true },
          });
        }
      }

      const warehouse = await this.prisma.warehouse.update({
        where: { id },
        data: updateWarehouseDto,
        select: warehouseSelect,
      });
      return warehouse;
    } catch (error) {
      throw handlePrismaError(error);
    }
  }

  async remove(id: string) {
    try {
      const warehouse = await this.prisma.warehouse.findUnique({
        where: { id },
      });

      if (warehouse && warehouse.readerId) {
        await this.prisma.reader.update({
          where: { id: warehouse.readerId },
          data: { status: false },
        });
      }

      await this.prisma.warehouse.delete({ where: { id } });
      return { message: 'Warehouse deleted successfully' };
    } catch (error) {
      throw handlePrismaError(error);
    }
  }

  async moveCylinders(moveCylindersDto: MoveCylindersDto) {
    const { warehouseId, cylinderIds } = moveCylindersDto;

    try {
      const warehouse = await this.prisma.warehouse.findUniqueOrThrow({
        where: { id: warehouseId },
      });

      return await this.prisma.$transaction(async (tx) => {
        await tx.cylinders.updateMany({
          where: {
            id: {
              in: cylinderIds,
            },
          },
          data: {
            warehouseId,
          },
        });

        const logs = cylinderIds.map((cylinderId) => ({
          cylinderId,
          warehouse: warehouse.name,
          movement: CylinderMovement.INSIDE,
          remark: `Cylinder Moved to ${warehouse.name}`,
        }));

        await tx.cylinder_logs.createMany({
          data: logs,
        });

        return { message: 'Cylinders moved successfully' };
      });
    } catch (error) {
      throw handlePrismaError(error);
    }
  }

  async getAllWarehouses(page: number, perPage: number, search?: string) {
    try {
      const { skip, take } = getPaginationOptions({ page, perPage });

      const where: any = {};

      if (search) {
        search = search.trim();
        where.OR = [
          { name: { contains: search } },
          { location: { contains: search } },
        ];
      }

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

      return formatPaginatedResponse(items, total, page, perPage);
    } catch (error) {
      console.log("error", error);
      handlePrismaError(error, 'Fetching paginated Warehouses');
    }
  }


}
