import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../database/prisma.service';
import { CreateOrderCustomerDto } from './dto/create-order-customer.dto';
import { UpdateCustomerDto } from './dto/update-customer.dto';
import { CustomerFilterDto } from './dto/customer-filter.dto';
import { CustomerCursor } from './dto/customer-cursor.dto';

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

  async findAll(filters: CustomerFilterDto) {
    const limit = filters.limit ?? 50;

    let cursor: CustomerCursor | null = null;

    if (filters.cursor) {
      try {
        const decoded = Buffer.from(filters.cursor, 'base64').toString('utf8');
        cursor = JSON.parse(decoded) as CustomerCursor;
      } catch {
        throw new Error('Invalid cursor');
      }
    }

    const where: any = {};

    if (filters.status) {
      where.status = filters.status;
    }

    if (cursor) {
      where.OR = [
        {
          createdAt: {
            lt: new Date(cursor.createdAt),
          },
        },
        {
          createdAt: new Date(cursor.createdAt),
          id: {
            lt: cursor.id,
          },
        },
      ];
    }

    const customers = await this.prisma.customer.findMany({
      where,
      orderBy: [
        {
          createdAt: 'desc',
        },
        {
          id: 'desc',
        },
      ],
      take: limit + 1,
      include: {
        lead: true,
      },
    });

    const hasNextPage = customers.length > limit;

    if (hasNextPage) {
      customers.pop();
    }

    const lastCustomer = customers[customers.length - 1];

    const nextCursor =
      hasNextPage && lastCustomer
        ? Buffer.from(
            JSON.stringify({
              createdAt: lastCustomer.createdAt.toISOString(),
              id: lastCustomer.id,
            }),
          ).toString('base64')
        : null;

    return {
      data: customers,
      pagination: {
        limit,
        nextCursor,
        hasNextPage,
      },
    };
  }

  async findOne(id: number) {
    const customer = await this.prisma.customer.findUnique({
      where: {
        id,
      },
      include: {
        lead: true,
      },
    });

    if (!customer) {
      throw new NotFoundException(`Customer with id ${id} not found`);
    }

    return customer;
  }

  async createOrder(dto: CreateOrderCustomerDto) {
    let lead = await this.prisma.lead.findUnique({
      where: {
        phone: dto.phone,
      },
    });

    if (!lead) {
      lead = await this.prisma.lead.create({
        data: {
          name: dto.name,
          product: dto.product,
          phone: dto.phone,
          email: dto.email,
          operator: dto.operator,
          comment: dto.comment,
          source: dto.source,
        },
      });
    }

    const customer = await this.prisma.customer.create({
      data: {
        name: dto.name,
        product: dto.product,
        phone: dto.phone,
        email: dto.email,
        status: dto.status,
        operator: dto.operator,
        comment: dto.comment,
        source: dto.source,
        leadId: lead.id,
      },
      include: {
        lead: true,
      },
    });

    return customer;
  }

  async update(id: number, dto: UpdateCustomerDto) {
    await this.findOne(id);

    return this.prisma.customer.update({
      where: {
        id,
      },
      data: dto,
      include: {
        lead: true,
      },
    });
  }
}
