import { WorkflowRequest } from '@models/WorkflowRequest';
import { Op } from 'sequelize';
import logger from './logger';

/**
 * Generate request number in format: REQ-YYYY-MM-XXXX
 * Counter resets every month
 * Example: REQ-2025-11-0001
 */
export const generateRequestNumber = async (): Promise<string> => {
  const now = new Date();
  const year = now.getFullYear();
  const month = (now.getMonth() + 1).toString().padStart(2, '0'); // Month is 0-indexed, so add 1
  
  // Build the prefix pattern for current year-month
  const prefix = `REQ-${year}-${month}-`;
  
  try {
    // Find the highest counter for the current year-month
    const existingRequests = await WorkflowRequest.findAll({
      where: {
        requestNumber: {
          [Op.like]: `${prefix}%`
        }
      },
      attributes: ['requestNumber'],
      order: [['requestNumber', 'DESC']],
      limit: 1
    });
    
    let counter = 1;
    
    if (existingRequests.length > 0) {
      // Extract the counter from the last request number
      const lastRequestNumber = (existingRequests[0] as any).requestNumber;
      const lastCounter = parseInt(lastRequestNumber.replace(prefix, ''), 10);
      
      if (!isNaN(lastCounter)) {
        counter = lastCounter + 1;
      }
    }
    
    // Format counter as 4-digit number (0001, 0002, etc.)
    const counterStr = counter.toString().padStart(4, '0');
    
    return `${prefix}${counterStr}`;
  } catch (error) {
    // Fallback to timestamp-based counter if database query fails
    logger.error('Error generating request number:', error);
    const fallbackCounter = Date.now().toString().slice(-4);
    return `${prefix}${fallbackCounter}`;
  }
};

export const calculateTATDays = (tatHours: number): number => {
  return Math.ceil(tatHours / 24);
};

export const calculateElapsedHours = (startTime: Date, endTime?: Date): number => {
  const end = endTime || new Date();
  const diffMs = end.getTime() - startTime.getTime();
  return Math.round((diffMs / (1000 * 60 * 60)) * 100) / 100; // Round to 2 decimal places
};

export const calculateTATPercentage = (elapsedHours: number, totalTatHours: number): number => {
  if (totalTatHours === 0) return 0;
  return Math.min(Math.round((elapsedHours / totalTatHours) * 100), 100);
};

export const isTATBreached = (elapsedHours: number, totalTatHours: number): boolean => {
  return elapsedHours > totalTatHours;
};

export const isTATApproaching = (elapsedHours: number, totalTatHours: number, threshold: number = 80): boolean => {
  const percentage = calculateTATPercentage(elapsedHours, totalTatHours);
  return percentage >= threshold && percentage < 100;
};

export const formatDate = (date: Date): string => {
  return date.toISOString().split('T')[0];
};

export const formatDateTime = (date: Date): string => {
  return date.toISOString();
};

export const isValidEmail = (email: string): boolean => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

export const isValidUUID = (uuid: string): boolean => {
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
  return uuidRegex.test(uuid);
};

export const sanitizeString = (str: string): string => {
  return str.trim().replace(/[<>]/g, '');
};

export const generateChecksum = (data: string): string => {
  const crypto = require('crypto');
  return crypto.createHash('sha256').update(data).digest('hex');
};

export const sleep = (ms: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

/**
 * Pad dealer code to 6 digits with leading zeros
 * Example: '73' -> '000073'
 */
export const padDealerCode = (dealerCode: string | number): string => {
  if (dealerCode === null || dealerCode === undefined) return '';
  return String(dealerCode).padStart(6, '0');
};

/**
 * WFM incoming claim CSV headers in required fixed order.
 */
export const WFM_CLAIM_CSV_HEADERS = [
  'TRNS_UNIQ_NO',
  'CLAIM_NUMBER',
  'INV_NUMBER',
  'INV_DATE',
  'DEALER_CODE',
  'IO_NUMBER',
  'CLAIM_DOC_TYP',
  'CLAIM_TYPE',
  'CLAIM_DATE',
  'HSN_CODE',
  'SAC_CODE',
  'PART_AMT',
  'LABOUR_AMT',
  'GST_AMT',
  'GST_PERCENTAGE',
] as const;

type WfmInvoiceItemLike = {
  transactionCode?: string;
  hsnCd?: string;
  assAmt?: number | string;
  gstRt?: number | string;
  igstAmt?: number | string;
  cgstAmt?: number | string;
  sgstAmt?: number | string;
  utgstAmt?: number | string;
  isServc?: string;
};

type BuildWfmRowInput = {
  item: WfmInvoiceItemLike;
  requestNumber: string;
  invoiceNumber: string;
  invoiceDate: Date;
  dealerCode: string;
  ioNumber: string;
  claimDocTyp: string;
  claimType: string;
};

/**
 * Build one WFM incoming claim CSV row.
 * Business rule:
 * - Service line -> SAC_CODE + LABOUR_AMT, keep HSN_CODE + PART_AMT empty
 * - Material line -> HSN_CODE + PART_AMT, keep SAC_CODE + LABOUR_AMT empty
 */
export const buildWfmClaimCsvRow = ({
  item,
  requestNumber,
  invoiceNumber,
  invoiceDate,
  dealerCode,
  ioNumber,
  claimDocTyp,
  claimType,
}: BuildWfmRowInput): Record<(typeof WFM_CLAIM_CSV_HEADERS)[number], string | number> => {
  const d = new Date(invoiceDate);
  const invDate = `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, '0')}${String(d.getDate()).padStart(2, '0')}`;
  const normalizedIsService = String(item.isServc || '').toUpperCase() === 'Y';
  const hsnOrSac = item.hsnCd || '';
  const assesableAmount = Number(item.assAmt || 0);
  const totalTax =
    Number(item.igstAmt || 0) +
    Number(item.cgstAmt || 0) +
    Number(item.sgstAmt || 0) +
    Number(item.utgstAmt || 0);

  return {
    TRNS_UNIQ_NO: item.transactionCode || '',
    CLAIM_NUMBER: requestNumber || '',
    INV_NUMBER: invoiceNumber || '',
    INV_DATE: invDate,
    DEALER_CODE: padDealerCode(dealerCode || ''),
    IO_NUMBER: ioNumber || '',
    CLAIM_DOC_TYP: claimDocTyp || '',
    CLAIM_TYPE: claimType || '',
    CLAIM_DATE: invDate,
    HSN_CODE: normalizedIsService ? '' : hsnOrSac,
    SAC_CODE: normalizedIsService ? hsnOrSac : '',
    PART_AMT: normalizedIsService ? '' : assesableAmount.toFixed(2),
    LABOUR_AMT: normalizedIsService ? assesableAmount.toFixed(2) : '',
    GST_AMT: totalTax.toFixed(2),
    GST_PERCENTAGE: item.gstRt ?? '',
  };
};
