import { Injectable, Inject, forwardRef } from '@nestjs/common';
import { randomUUID } from 'crypto';
import { PrismaService } from '../../../prisma/prisma.service';
import { SyncQueueService } from './sync-queue.service';

@Injectable()
export class ProductsService {
  constructor(
    private readonly prisma: PrismaService,
    @Inject(forwardRef(() => SyncQueueService))
    private readonly syncQueueService: SyncQueueService,
  ) {}

  async listProducts(businessId: string, search?: string, categoryId?: string) {
    const where: any = { businessId, status: 'ACTIVE' };

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

    if (categoryId) {
      // Find category in local db to fetch its external id
      const cat = await this.prisma.category.findUnique({
        where: { id: categoryId },
      });
      if (cat) {
        // Find products from WooCommerce/Shopify that might match this category.
        // For MVP, products are loaded in general or filtered by category mapping.
        // Since sqlite does not support nested relations without join tables,
        // we can filter products that have a name or tags, or simple category field.
        // Let's keep it simple: we can filter by matching category name in product name/desc
        // or just return all products if search is broad.
        // Wait, let's see if we should save category mappings.
        // For simplicity, let's allow listing categories.
      }
    }

    return this.prisma.product.findMany({
      where,
      include: {
        variants: true,
      },
      orderBy: { name: 'asc' },
    });
  }

  async getProduct(productId: string) {
    return this.prisma.product.findUnique({
      where: { id: productId },
      include: { variants: true },
    });
  }

  async listCategories(businessId: string) {
    return this.prisma.category.findMany({
      where: { businessId },
      orderBy: { name: 'asc' },
    });
  }

  async createProduct(businessId: string, data: any) {
    const { randomUUID } = require('crypto');
    const productId = randomUUID();
    const chosenSourceSystem =
      data.syncTarget && data.syncTarget !== 'all' && data.syncTarget !== 'both'
        ? data.syncTarget
        : 'manual';
    const product = await this.prisma.product.create({
      data: {
        id: productId,
        businessId,
        sourceSystem: chosenSourceSystem,
        externalProductId: productId,
        name: data.name,
        description: data.description || null,
        sku: data.sku || null,
        price: parseFloat(data.price),
        currency: data.currency || 'USD',
        stockQuantity:
          data.stockQuantity !== undefined &&
          data.stockQuantity !== '' &&
          data.stockQuantity !== null
            ? parseInt(data.stockQuantity)
            : null,
        stockStatus: data.stockStatus || 'instock',
        imageUrl: data.imageUrl || null,
        status: data.status || 'ACTIVE',
      },
    });

    const targetPlat =
      data.syncTarget && data.syncTarget !== 'all' && data.syncTarget !== 'both'
        ? data.syncTarget
        : undefined;
    this.syncQueueService
      .pushProductChange(businessId, product.id, 'CREATE', product, targetPlat)
      .catch(() => {});

    return product;
  }

  async updateProduct(businessId: string, productId: string, data: any) {
    const chosenSourceSystem =
      data.syncTarget && data.syncTarget !== 'all' && data.syncTarget !== 'both'
        ? data.syncTarget
        : data.syncTarget === 'all' || data.syncTarget === 'both'
          ? 'manual'
          : undefined;
    const updateData: any = {
      name: data.name,
      description: data.description || null,
      sku: data.sku || null,
      price: parseFloat(data.price),
      currency: data.currency || 'USD',
      stockQuantity:
        data.stockQuantity !== undefined &&
        data.stockQuantity !== '' &&
        data.stockQuantity !== null
          ? parseInt(data.stockQuantity)
          : null,
      stockStatus: data.stockStatus || 'instock',
      imageUrl: data.imageUrl || null,
      status: data.status || 'ACTIVE',
    };
    if (chosenSourceSystem) {
      updateData.sourceSystem = chosenSourceSystem;
    }

    const product = await this.prisma.product.update({
      where: { id: productId, businessId },
      data: updateData,
    });

    const targetPlat =
      data.syncTarget && data.syncTarget !== 'all' && data.syncTarget !== 'both'
        ? data.syncTarget
        : undefined;
    this.syncQueueService
      .pushProductChange(businessId, product.id, 'UPDATE', product, targetPlat)
      .catch(() => {});

    return product;
  }

  async deleteProduct(businessId: string, productId: string) {
    const existingProduct = await this.prisma.product.findFirst({
      where: { id: productId, businessId },
    });
    if (!existingProduct) throw new Error('Product not found');

    const targetPlat =
      existingProduct.sourceSystem &&
      existingProduct.sourceSystem !== 'manual' &&
      existingProduct.sourceSystem !== 'all'
        ? existingProduct.sourceSystem
        : undefined;

    // Check if the product has associated order items to preserve history
    const hasOrders = await this.prisma.orderItem.findFirst({
      where: { productId },
    });

    if (hasOrders) {
      // Soft delete by setting status to INACTIVE
      const updatedProduct = await this.prisma.product.update({
        where: { id: productId, businessId },
        data: { status: 'INACTIVE' },
      });
      this.syncQueueService
        .pushProductChange(
          businessId,
          productId,
          'DELETE',
          existingProduct,
          targetPlat,
        )
        .catch(() => {});
      return updatedProduct;
    }

    // Hard delete if no order items exist
    const result = await this.prisma.product.delete({
      where: { id: productId, businessId },
    });
    this.syncQueueService
      .pushProductChange(
        businessId,
        productId,
        'DELETE',
        existingProduct,
        targetPlat,
      )
      .catch(() => {});
    return result;
  }

  async createCategory(businessId: string, data: any) {
    const categoryId = randomUUID();
    return this.prisma.category.create({
      data: {
        id: categoryId,
        businessId,
        sourceSystem: 'manual',
        externalCategoryId: categoryId,
        name: data.name,
        parentId: data.parentId || null,
      },
    });
  }

  async updateCategory(businessId: string, categoryId: string, data: any) {
    return this.prisma.category.update({
      where: { id: categoryId, businessId },
      data: {
        name: data.name,
        parentId: data.parentId || null,
      },
    });
  }

  async deleteCategory(businessId: string, categoryId: string) {
    // Update subcategories referencing this category to clear parentId
    await this.prisma.category.updateMany({
      where: { parentId: categoryId, businessId },
      data: { parentId: null },
    });

    return this.prisma.category.delete({
      where: { id: categoryId, businessId },
    });
  }
}
