const db = require('../models');
const { sendResponse, sendError } = require('../utils/response');
const asyncHandler = require('../middlewares/asyncHandler');
const { getPagination, getPagingData } = require('../utils/pagination');
const { Op } = require('sequelize');

exports.getAll = asyncHandler(async (req, res) => {
  const { page = 1, limit = 25, search, companyId, plantId, fiscalYearId, productionOrderId, asOnDate, source } = req.query;
  const { limit: limitNum, offset } = getPagination(page, limit);

  if (String(source || '').toUpperCase() === 'REAL') {
    const routeCardWhere = {};
    if (companyId) {
      routeCardWhere.company_id = companyId;
    } else if (req.user && !req.user.isSuperAdmin) {
      routeCardWhere.company_id = req.user.companyId;
    }
    if (plantId) routeCardWhere.plant_id = plantId;
    if (fiscalYearId) routeCardWhere.fiscal_year_id = fiscalYearId;
    if (productionOrderId) routeCardWhere.production_order_id = productionOrderId;

    const opRows = await db.RouteCardOperation.findAll({
      include: [
        {
          model: db.RouteCard,
          as: 'routeCard',
          where: routeCardWhere,
          attributes: ['id', 'production_order_id', 'finished_material_id', 'company_id', 'plant_id', 'fiscal_year_id'],
          include: [
            { model: db.ProductionOrder, as: 'productionOrder', attributes: ['id', 'production_order_number'] },
            { model: db.Material, as: 'finishedMaterial', attributes: ['id', 'material_number', 'description', 'base_uom_id'], include: [{ model: db.UOM, as: 'baseUOM', attributes: ['id', 'uom_code', 'uom_name'] }] }
          ]
        }
      ],
      order: [[{ model: db.RouteCard, as: 'routeCard' }, 'id', 'DESC']]
    });

    const today = new Date().toISOString().slice(0, 10);
    const map = new Map();
    opRows.forEach((op) => {
      const row = typeof op.toJSON === 'function' ? op.toJSON() : op;
      const rc = row.routeCard || {};
      const po = rc.productionOrder || {};
      const material = rc.finishedMaterial || {};
      const uom = material.baseUOM || null;
      const key = `${po.id || rc.production_order_id || 'NA'}_${material.id || rc.finished_material_id || 'NA'}`;
      if (!map.has(key)) {
        map.set(key, {
          id: key,
          source: 'REAL',
          company_id: rc.company_id || null,
          plant_id: rc.plant_id || null,
          fiscal_year_id: rc.fiscal_year_id || null,
          production_order_id: po.id || rc.production_order_id || null,
          material_id: material.id || rc.finished_material_id || null,
          productionOrder: po?.id ? po : null,
          material: material?.id ? material : null,
          uom_id: uom?.id || null,
          uom: uom,
          wip_quantity: 0,
          rework_qty: 0,
          open_operation_count: 0,
          material_value: 0,
          labor_value: 0,
          overhead_value: 0,
          total_wip_value: 0,
          as_on_date: today,
          remarks: 'Auto-calculated from Route Card operations'
        });
      }
      const agg = map.get(key);
      const inputQty = parseFloat(row.input_qty || 0);
      const completedQty = parseFloat(row.completed_qty || 0);
      const reworkQty = parseFloat(row.rework_qty || 0);
      const pendingQty = Math.max(inputQty - completedQty, 0);
      agg.wip_quantity += pendingQty + reworkQty;
      agg.rework_qty += reworkQty;
      if (!['COMPLETED', 'CANCELLED', 'SKIPPED'].includes(String(row.status || '').toUpperCase())) {
        agg.open_operation_count += 1;
      }
    });

    let items = Array.from(map.values()).map((r) => ({
      ...r,
      wip_quantity: Math.round((parseFloat(r.wip_quantity || 0) + Number.EPSILON) * 1000) / 1000,
      rework_qty: Math.round((parseFloat(r.rework_qty || 0) + Number.EPSILON) * 1000) / 1000
    }));

    if (asOnDate) {
      items = items.filter((r) => String(r.as_on_date) === String(asOnDate));
    }
    if (search) {
      const q = String(search).trim().toLowerCase();
      items = items.filter((r) => {
        const poNo = String(r?.productionOrder?.production_order_number || '').toLowerCase();
        const matNo = String(r?.material?.material_number || '').toLowerCase();
        const matDesc = String(r?.material?.description || '').toLowerCase();
        return poNo.includes(q) || matNo.includes(q) || matDesc.includes(q);
      });
    }

    items.sort((a, b) => String(b.as_on_date).localeCompare(String(a.as_on_date)));
    const totalItems = items.length;
    const paged = items.slice(offset, offset + limitNum);

    return sendResponse(res, 200, true, 'WIP Tracking (real-time) retrieved successfully', {
      totalItems,
      items: paged,
      totalPages: Math.ceil(totalItems / limitNum),
      currentPage: parseInt(page, 10)
    });
  }

  const where = {};
  
  if (companyId) {
    where.company_id = companyId;
  } else if (req.user && !req.user.isSuperAdmin) {
    where.company_id = req.user.companyId;
  }

  if (plantId) {
    where.plant_id = plantId;
  }

  if (fiscalYearId) {
    where.fiscal_year_id = fiscalYearId;
  }

  if (productionOrderId) {
    where.production_order_id = productionOrderId;
  }

  if (asOnDate) {
    where.as_on_date = asOnDate;
  }

  const records = await db.WIPTracking.findAndCountAll({
    where,
    include: [
      { model: db.Company, as: 'company', attributes: ['id', 'code', 'name'] },
      { model: db.Plant, as: 'plant', attributes: ['id', 'code', 'name'] },
      { model: db.ProductionOrder, as: 'productionOrder', attributes: ['id', 'production_order_number'] },
      { model: db.Material, as: 'material', attributes: ['id', 'material_number', 'description'] }
    ],
    limit: limitNum,
    offset,
    order: [['as_on_date', 'DESC'], ['id', 'DESC']]
  });

  const response = getPagingData(records, page, limitNum);
  sendResponse(res, 200, true, 'WIP Tracking records retrieved successfully', response);
});

exports.getById = asyncHandler(async (req, res) => {
  const { id } = req.params;

  const wip = await db.WIPTracking.findByPk(id, {
    include: [
      { model: db.Company, as: 'company' },
      { model: db.Plant, as: 'plant' },
      { model: db.FiscalYear, as: 'fiscalYear' },
      { model: db.ProductionOrder, as: 'productionOrder' },
      { model: db.Material, as: 'material' },
      { model: db.UOM, as: 'uom' }
    ]
  });

  if (!wip) {
    return sendError(res, 'WIP Tracking record not found', 404);
  }

  sendResponse(res, 200, true, 'WIP Tracking record retrieved successfully', wip);
});

exports.create = asyncHandler(async (req, res) => {
  const data = req.body;
  const userId = req.user?.userId || null;
  const companyId = req.user?.companyId;

  if (!companyId) {
    return sendError(res, 'Company ID is required', 400);
  }

  if (!data.plant_id || !data.fiscal_year_id || !data.production_order_id || !data.material_id) {
    return sendError(res, 'Plant ID, Fiscal Year ID, Production Order ID, and Material ID are required', 400);
  }

  data.company_id = companyId;

  const materialValue = parseFloat(data.material_value) || 0;
  const laborValue = parseFloat(data.labor_value) || 0;
  const overheadValue = parseFloat(data.overhead_value) || 0;
  data.total_wip_value = materialValue + laborValue + overheadValue;

  const wip = await db.WIPTracking.create(data);

  const createdWip = await db.WIPTracking.findByPk(wip.id, {
    include: [
      { model: db.Company, as: 'company' },
      { model: db.Plant, as: 'plant' },
      { model: db.ProductionOrder, as: 'productionOrder' },
      { model: db.Material, as: 'material' }
    ]
  });

  sendResponse(res, 201, true, 'WIP Tracking record created successfully', createdWip);
});

exports.update = asyncHandler(async (req, res) => {
  const { id } = req.params;
  const data = req.body;

  const wip = await db.WIPTracking.findByPk(id);
  if (!wip) {
    return sendError(res, 'WIP Tracking record not found', 404);
  }

  const materialValue = parseFloat(data.material_value) || 0;
  const laborValue = parseFloat(data.labor_value) || 0;
  const overheadValue = parseFloat(data.overhead_value) || 0;
  data.total_wip_value = materialValue + laborValue + overheadValue;

  await wip.update(data);

  const updatedWip = await db.WIPTracking.findByPk(id, {
    include: [
      { model: db.Company, as: 'company' },
      { model: db.Plant, as: 'plant' },
      { model: db.ProductionOrder, as: 'productionOrder' },
      { model: db.Material, as: 'material' }
    ]
  });

  sendResponse(res, 200, true, 'WIP Tracking record updated successfully', updatedWip);
});

exports.delete = asyncHandler(async (req, res) => {
  const { id } = req.params;

  const wip = await db.WIPTracking.findByPk(id);
  if (!wip) {
    return sendError(res, 'WIP Tracking record not found', 404);
  }

  await wip.destroy();

  sendResponse(res, 200, true, 'WIP Tracking record deleted successfully');
});

