const db = require('../models');
const { Op } = require('sequelize');

/**
 * Generate next material number based on company and material type
 * @param {number} companyId - Company ID
 * @param {number} materialTypeId - Material Type ID
 * @returns {Promise<string>} Generated material number
 */
async function generateMaterialNumber(companyId, materialTypeId) {
  try {
    // Get company code
    const company = await db.Company.findByPk(companyId, {
      attributes: ['id', 'code', 'name']
    });

    if (!company) {
      throw new Error('Company not found');
    }

    // Get material type code
    const materialType = await db.MaterialType.findByPk(materialTypeId, {
      attributes: ['id', 'type_code', 'type_name']
    });

    if (!materialType) {
      throw new Error('Material type not found');
    }

    // Find or create number format for this company + material type
    let numberFormat = await db.NumberFormat.findOne({
      where: {
        company_id: companyId,
        module_name: 'MATERIAL',
        material_type_id: materialTypeId,
        is_active: true,
        status: 'ACTIVE'
      },
      include: [
        { model: db.Company, as: 'company', attributes: ['code'] },
        { model: db.MaterialType, as: 'materialType', attributes: ['type_code'] }
      ]
    });

    // If format doesn't exist, create default one
    if (!numberFormat) {
      const defaultFormat = {
        company_id: companyId,
        module_name: 'MATERIAL',
        material_type_id: materialTypeId,
        format_pattern: '{COMPANY_CODE}{SEPARATOR}{MATERIAL_TYPE_CODE}{SEPARATOR}{SEQUENCE}',
        sequence_length: 6,
        separator: '-',
        current_sequence: 0,
        reset_period: 'NEVER',
        is_active: true,
        status: 'ACTIVE',
        description: `Auto-generated format for ${company.name} - ${materialType.type_name}`
      };

      numberFormat = await db.NumberFormat.create(defaultFormat);
    }

    // Check if sequence needs to be reset
    const now = new Date();
    let shouldReset = false;

    if (numberFormat.reset_period === 'YEARLY') {
      const lastReset = numberFormat.last_reset_date 
        ? new Date(numberFormat.last_reset_date) 
        : null;
      if (!lastReset || lastReset.getFullYear() < now.getFullYear()) {
        shouldReset = true;
      }
    } else if (numberFormat.reset_period === 'MONTHLY') {
      const lastReset = numberFormat.last_reset_date 
        ? new Date(numberFormat.last_reset_date) 
        : null;
      if (!lastReset || 
          lastReset.getFullYear() < now.getFullYear() || 
          lastReset.getMonth() < now.getMonth()) {
        shouldReset = true;
      }
    } else if (numberFormat.reset_period === 'DAILY') {
      const lastReset = numberFormat.last_reset_date 
        ? new Date(numberFormat.last_reset_date) 
        : null;
      if (!lastReset || lastReset.toDateString() !== now.toDateString()) {
        shouldReset = true;
      }
    }

    if (shouldReset) {
      numberFormat.current_sequence = 0;
      numberFormat.last_reset_date = now.toISOString().split('T')[0];
    }

    // Increment sequence
    numberFormat.current_sequence += 1;
    await numberFormat.save();

    // Generate the number
    const sequence = String(numberFormat.current_sequence).padStart(
      numberFormat.sequence_length, 
      '0'
    );

    let generatedNumber = numberFormat.format_pattern
      .replace(/{COMPANY_CODE}/g, company.code)
      .replace(/{MATERIAL_TYPE_CODE}/g, materialType.type_code)
      .replace(/{SEQUENCE}/g, sequence)
      .replace(/{SEPARATOR}/g, numberFormat.separator);

    // Add prefix and suffix if specified
    if (numberFormat.prefix) {
      generatedNumber = numberFormat.prefix + numberFormat.separator + generatedNumber;
    }
    if (numberFormat.suffix) {
      generatedNumber = generatedNumber + numberFormat.separator + numberFormat.suffix;
    }

    return generatedNumber;
  } catch (error) {
    console.error('Error generating material number:', error);
    throw error;
  }
}

/**
 * Get number format for a company and material type
 * @param {number} companyId - Company ID
 * @param {number} materialTypeId - Material Type ID
 * @returns {Promise<Object>} Number format configuration
 */
async function getMaterialNumberFormat(companyId, materialTypeId) {
  try {
    let numberFormat = await db.NumberFormat.findOne({
      where: {
        company_id: companyId,
        module_name: 'MATERIAL',
        material_type_id: materialTypeId,
        is_active: true,
        status: 'ACTIVE'
      },
      include: [
        { model: db.Company, as: 'company', attributes: ['id', 'code', 'name'] },
        { model: db.MaterialType, as: 'materialType', attributes: ['id', 'type_code', 'type_name'] }
      ]
    });

    // If format doesn't exist, return default preview
    if (!numberFormat) {
      const company = await db.Company.findByPk(companyId, {
        attributes: ['id', 'code', 'name']
      });
      const materialType = await db.MaterialType.findByPk(materialTypeId, {
        attributes: ['id', 'type_code', 'type_name']
      });

      if (!company || !materialType) {
        return null;
      }

      return {
        format_pattern: '{COMPANY_CODE}-{MATERIAL_TYPE_CODE}-{SEQUENCE}',
        sequence_length: 6,
        separator: '-',
        preview: `${company.code}-${materialType.type_code}-000001`,
        company: company,
        materialType: materialType
      };
    }

    // Generate preview
    const sequence = String(numberFormat.current_sequence + 1).padStart(
      numberFormat.sequence_length, 
      '0'
    );

    let preview = numberFormat.format_pattern
      .replace(/{COMPANY_CODE}/g, numberFormat.company.code)
      .replace(/{MATERIAL_TYPE_CODE}/g, numberFormat.materialType.type_code)
      .replace(/{SEQUENCE}/g, sequence)
      .replace(/{SEPARATOR}/g, numberFormat.separator);

    if (numberFormat.prefix) {
      preview = numberFormat.prefix + numberFormat.separator + preview;
    }
    if (numberFormat.suffix) {
      preview = preview + numberFormat.separator + numberFormat.suffix;
    }

    return {
      ...numberFormat.toJSON(),
      preview: preview
    };
  } catch (error) {
    console.error('Error getting material number format:', error);
    throw error;
  }
}

module.exports = {
  generateMaterialNumber,
  getMaterialNumberFormat
};

