import { Test, TestingModule } from '@nestjs/testing';
import { getModelToken } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import { describe, it, expect, beforeEach } from 'vitest';
import { ItemsService } from './items.service';
import { Item } from './schemas/item.schema';
import { Batch } from './schemas/batch.schema';
import { InventoryBalance } from './schemas/inventory-balance.schema';
import { StockMovementSheet } from './schemas/stock-movement-sheet.schema';

/**
 * Bug Condition Exploration Test for Stock-Out UI Available MT Display
 * 
 * Property 1: Bug Condition - Multi-Warehouse Batch Returns Global MT Instead of Warehouse-Specific MT
 * 
 * CRITICAL: This test MUST FAIL on unfixed code - failure confirms the bug exists
 * 
 * Goal: Surface counterexamples that demonstrate the bug exists
 * 
 * Bug Description:
 * When findBatches(itemId, warehouseId) is called for a batch distributed across multiple warehouses,
 * the returned availableMt should be warehouse-specific, not the global total.
 * 
 * Example:
 * - Abu Dhabi Musaffah: 1,000 bags × 20kg = 20 MT
 * - Dubai Warehouse: 10,000 bags × 20kg = 200 MT
 * - Sharjah Warehouse: 11,000 bags × 20kg = 220 MT
 * - Total: 22,000 bags × 20kg = 440 MT
 * 
 * Expected: findBatches returns 20 MT for Abu Dhabi
 * Actual (buggy): findBatches returns 440 MT (global total)
 */

describe('ItemsService - Bug Condition Exploration (findBatches)', () => {
  let service: ItemsService;
  let itemModel: any;
  let batchModel: any;
  let balanceModel: any;
  let sheetModel: any;

  // Test data IDs
  const itemId = new Types.ObjectId();
  const warehouseAbuDhabiId = new Types.ObjectId();
  const warehouseDubaiId = new Types.ObjectId();
  const warehouseSharjahId = new Types.ObjectId();
  const batchId = new Types.ObjectId();

  beforeEach(async () => {
    // Mock models
    itemModel = {
      findById: () => ({
        lean: () => ({
          exec: async () => ({
            _id: itemId,
            itemCode: 'RICE-NAJAM-20KG',
            itemName: 'Rice - Najam - 20 Kg',
            bagWeightKg: 20,
          }),
        }),
      }),
    };

    batchModel = {
      find: () => ({
        lean: () => ({
          exec: async () => [
            {
              _id: batchId,
              itemId: itemId,
              warehouseId: warehouseAbuDhabiId,
              batchNumber: 'BATCH-12',
              expiryDate: '2025-12-31',
              stockedOut: false,
            },
          ],
        }),
      }),
    };

    balanceModel = {
      findOne: () => ({
        lean: () => ({
          exec: async () => null, // No balance record (we're using sheets as primary source)
        }),
      }),
    };

    // Mock approved sheet with multi-warehouse distribution
    sheetModel = {
      find: () => ({
        lean: () => ({
          exec: async () => [
            {
              _id: new Types.ObjectId(),
              approvalStatus: 'approved',
              lineItems: [
                {
                  itemId: itemId,
                  itemCode: 'RICE-NAJAM-20KG',
                  itemName: 'Rice - Najam - 20 Kg',
                  batchNumber: 'BATCH-12',
                  expiryDate: '2025-12-31',
                  warehouseBags: {
                    [warehouseAbuDhabiId.toString()]: 1000,  // 1,000 bags in Abu Dhabi
                    [warehouseDubaiId.toString()]: 10000,    // 10,000 bags in Dubai
                    [warehouseSharjahId.toString()]: 11000,  // 11,000 bags in Sharjah
                  },
                  totalBags: 22000,
                  totalMt: 440, // Total across all warehouses: 22,000 bags × 20kg / 1000 = 440 MT
                  unit: 'BAG/1x20kg',
                },
              ],
            },
          ],
        }),
      }),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        ItemsService,
        { provide: getModelToken(Item.name), useValue: itemModel },
        { provide: getModelToken(Batch.name), useValue: batchModel },
        { provide: getModelToken(InventoryBalance.name), useValue: balanceModel },
        { provide: getModelToken(StockMovementSheet.name), useValue: sheetModel },
      ],
    }).compile();

    service = module.get<ItemsService>(ItemsService);
  });

  it('should return warehouse-specific MT (20 MT) for Abu Dhabi, not global total (440 MT)', async () => {
    // Act: Call findBatches for Abu Dhabi warehouse
    const result = await service.findBatches(
      itemId.toString(),
      warehouseAbuDhabiId.toString()
    );

    // Assert: Should return warehouse-specific MT
    expect(result).toHaveLength(1);
    expect(result[0].batchNumber).toBe('BATCH-12');
    
    // CRITICAL ASSERTION: This should be 20 MT (warehouse-specific), not 440 MT (global total)
    // Expected: 1,000 bags × 20kg / 1000 = 20 MT
    // Actual (buggy): 440 MT (total across all warehouses)
    const expectedWarehouseSpecificMt = 20.0; // 1,000 bags × 20kg / 1000
    const actualMt = result[0].availableMt;

    console.log(`\n=== Bug Condition Exploration Results ===`);
    console.log(`Warehouse: Abu Dhabi Musaffah`);
    console.log(`Item: Rice - Najam - 20 Kg`);
    console.log(`Batch: BATCH-12`);
    console.log(`Expected MT (warehouse-specific): ${expectedWarehouseSpecificMt} MT`);
    console.log(`Actual MT (returned by findBatches): ${actualMt} MT`);
    console.log(`Bug exists: ${actualMt !== expectedWarehouseSpecificMt}`);
    console.log(`=========================================\n`);

    // This assertion SHOULD FAIL on unfixed code (confirming the bug exists)
    expect(actualMt).toBe(expectedWarehouseSpecificMt);
  });

  it('should return warehouse-specific MT (200 MT) for Dubai, not global total (440 MT)', async () => {
    // Update batch model to return Dubai warehouse batch
    batchModel.find = () => ({
      lean: () => ({
        exec: async () => [
          {
            _id: batchId,
            itemId: itemId,
            warehouseId: warehouseDubaiId,
            batchNumber: 'BATCH-12',
            expiryDate: '2025-12-31',
            stockedOut: false,
          },
        ],
      }),
    });

    // Act: Call findBatches for Dubai warehouse
    const result = await service.findBatches(
      itemId.toString(),
      warehouseDubaiId.toString()
    );

    // Assert: Should return warehouse-specific MT
    expect(result).toHaveLength(1);
    
    // Expected: 10,000 bags × 20kg / 1000 = 200 MT
    const expectedWarehouseSpecificMt = 200.0;
    const actualMt = result[0].availableMt;

    console.log(`\n=== Bug Condition Exploration Results (Dubai) ===`);
    console.log(`Warehouse: Dubai`);
    console.log(`Expected MT: ${expectedWarehouseSpecificMt} MT`);
    console.log(`Actual MT: ${actualMt} MT`);
    console.log(`Bug exists: ${actualMt !== expectedWarehouseSpecificMt}`);
    console.log(`=================================================\n`);

    expect(actualMt).toBe(expectedWarehouseSpecificMt);
  });

  it('should filter out batch when warehouse has zero bags', async () => {
    // Create a warehouse with zero bags (Fujairah)
    const warehouseFujairahId = new Types.ObjectId();

    // Update batch model to return Fujairah warehouse batch
    batchModel.find = () => ({
      lean: () => ({
        exec: async () => [
          {
            _id: batchId,
            itemId: itemId,
            warehouseId: warehouseFujairahId,
            batchNumber: 'BATCH-12',
            expiryDate: '2025-12-31',
            stockedOut: false,
          },
        ],
      }),
    });

    // Act: Call findBatches for Fujairah warehouse (which has 0 bags)
    const result = await service.findBatches(
      itemId.toString(),
      warehouseFujairahId.toString()
    );

    // Assert: Should return empty array (batch filtered out because availableMt = 0)
    // Buggy behavior: Returns batch with 440 MT (global total)
    console.log(`\n=== Bug Condition Exploration Results (Zero Bags) ===`);
    console.log(`Warehouse: Fujairah (0 bags)`);
    console.log(`Expected: Batch filtered out (empty array)`);
    console.log(`Actual: ${result.length} batch(es) returned`);
    if (result.length > 0) {
      console.log(`Actual MT: ${result[0].availableMt} MT (should be filtered out)`);
    }
    console.log(`Bug exists: ${result.length > 0}`);
    console.log(`=====================================================\n`);

    expect(result).toHaveLength(0);
  });

  it('should return correct MT for single-warehouse batch (works by coincidence)', async () => {
    // Create a batch that only exists in one warehouse
    const singleWarehouseId = new Types.ObjectId();
    const singleBatchId = new Types.ObjectId();

    batchModel.find = () => ({
      lean: () => ({
        exec: async () => [
          {
            _id: singleBatchId,
            itemId: itemId,
            warehouseId: singleWarehouseId,
            batchNumber: 'BATCH-99',
            expiryDate: '2025-12-31',
            stockedOut: false,
          },
        ],
      }),
    });

    // Mock sheet with single-warehouse distribution
    sheetModel.find = () => ({
      lean: () => ({
        exec: async () => [
          {
            _id: new Types.ObjectId(),
            approvalStatus: 'approved',
            lineItems: [
              {
                itemId: itemId,
                itemCode: 'RICE-NAJAM-20KG',
                itemName: 'Rice - Najam - 20 Kg',
                batchNumber: 'BATCH-99',
                expiryDate: '2025-12-31',
                warehouseBags: {
                  [singleWarehouseId.toString()]: 500, // Only 500 bags in this warehouse
                },
                totalBags: 500,
                totalMt: 10, // 500 bags × 20kg / 1000 = 10 MT
                unit: 'BAG/1x20kg',
              },
            ],
          },
        ],
      }),
    });

    // Act
    const result = await service.findBatches(
      itemId.toString(),
      singleWarehouseId.toString()
    );

    // Assert: This should pass even on buggy code (works by coincidence)
    expect(result).toHaveLength(1);
    expect(result[0].availableMt).toBe(10.0);

    console.log(`\n=== Single-Warehouse Batch (Works by Coincidence) ===`);
    console.log(`This test passes on both buggy and fixed code`);
    console.log(`because the batch only exists in one warehouse.`);
    console.log(`=====================================================\n`);
  });
});
