import fs from 'fs';
import { wfmFileService } from './wfmFile.service';
import { WorkflowRequest } from '../models/WorkflowRequest';
import { ClaimCreditNote } from '../models/ClaimCreditNote';
import { ClaimCreditNoteItem } from '../models/ClaimCreditNoteItem';
import { sequelize } from '@config/database';
import logger from '../utils/logger';

export class CreditNoteSyncService {
  /**
   * Main sync function to process all outgoing files
   */
  async syncCreditNotes(): Promise<void> {
    try {
      const gstFiles = wfmFileService.listOutgoingFiles(false);
      const nonGstFiles = wfmFileService.listOutgoingFiles(true);
      
      const allFiles = [
        ...gstFiles.map(f => ({ path: f, isNonGst: false })),
        ...nonGstFiles.map(f => ({ path: f, isNonGst: true }))
      ];

      if (allFiles.length === 0) return;

      logger.info(`[CreditNoteSyncService] Found ${allFiles.length} files to process`);

      for (const fileInfo of allFiles) {
        await this.processFile(fileInfo.path);
      }
    } catch (error) {
      logger.error('[CreditNoteSyncService] Error during sync:', error);
    }
  }

  /**
   * Process a single CSV file
   */
  async processFile(filePath: string): Promise<boolean> {
    try {
      if (!fs.existsSync(filePath)) return false;

      const fileContent = fs.readFileSync(filePath, 'utf-8');
      const lines = fileContent.split(/\r?\n/).filter(l => l.trim() !== '');
      if (lines.length <= 1) {
          // Empty or only headers - delete it
          fs.unlinkSync(filePath);
          logger.info(`[CreditNoteSyncService] Deleted empty/header-only file: ${filePath}`);
          return true;
      }

      const headers = lines[0].split('|').map(h => h.trim().toUpperCase());
      const rows = lines.slice(1).map(line => {
        const values = line.split('|');
        const row: any = {};
        headers.forEach((h, i) => { row[h] = values[i]?.trim() || ''; });
        return row;
      });

      // Group rows by CLAIM_NUMBER
      const groups: Record<string, any[]> = {};
      rows.forEach(row => {
        const claimNum = row.CLAIM_NUMBER;
        if (!claimNum) return;
        if (!groups[claimNum]) groups[claimNum] = [];
        groups[claimNum].push(row);
      });

      // Process each group
      let allProcessed = true;
      for (const [claimNumber, rows] of Object.entries(groups)) {
        const success = await this.processClaimGroup(claimNumber, rows, filePath);
        if (!success) {
          allProcessed = false;
          logger.warn(`[CreditNoteSyncService] Failed to process claim group ${claimNumber} in file ${filePath}`);
        }
      }

      if (allProcessed && rows.length > 0) {
        fs.unlinkSync(filePath);
        logger.info(`[CreditNoteSyncService] Successfully processed and deleted file: ${filePath}`);
        return true;
      }
      return false;
    } catch (error) {
      logger.error(`[CreditNoteSyncService] Error processing file ${filePath}:`, error);
      return false;
    }
  }

  private async processClaimGroup(claimNumber: string, rows: any[], filePath: string): Promise<boolean> {
    const t = await sequelize.transaction();
    try {
      // 1. Find the request by requestNumber (which is the CLAIM_NUMBER in CSV)
      const request = await WorkflowRequest.findOne({ where: { requestNumber: claimNumber }, transaction: t });
      if (!request) {
        logger.warn(`[CreditNoteSyncService] WorkflowRequest not found for claim number: ${claimNumber}`);
        await t.rollback();
        // We return true here because we might still want to delete the file if other claims are processed
        // or if this is a filtered/old claim we don't care about.
        return true; 
      }

      const requestId = request.requestId;

      // 2. Calculate totals
      let totalAmount = 0;
      let totalTds = 0;
      let totalCredit = 0;
      rows.forEach(row => {
        totalAmount += Number(row.CREDITED_TOTAL_AMT || row.CLAIM_AMT || row.CREDIT_AMT || 0);
        totalTds += Number(row.TDS_AMT || 0);
        totalCredit += Number(row.CREDITED_TOTAL_AMT || row.CREDIT_AMT || row.FINAL_AMT || 0);
      });

      const firstRow = rows[0];

      // 3. Upsert Header
      const [cnHeader] = await ClaimCreditNote.upsert({
        requestId,
        creditNoteNumber: firstRow.DOC_NO || firstRow.CREDIT_NOTE_NUMBER || undefined,
        sapDocumentNumber: firstRow.DOC_NO || firstRow.CREDIT_NOTE_NUMBER || undefined,
        status: firstRow.MSG_TYP || 'CONFIRMED',
        errorMessage: firstRow.MESSAGE || undefined,
        creditNoteFilePath: filePath,
        creditNoteAmount: totalAmount,
        transactionNo: firstRow.TRNS_UNIQ_NO || undefined,
        tdsAmount: totalTds,
        creditAmount: totalCredit,
        confirmedAt: new Date()
      }, { transaction: t, returning: true });

      // 4. Update Line Items
      // Clear existing items
      await ClaimCreditNoteItem.destroy({ where: { creditNoteId: cnHeader.creditNoteId }, transaction: t });
      
      // Bulk create new items
      const itemsToCreate = rows.map((row, index) => ({
        creditNoteId: cnHeader.creditNoteId,
        slNo: index + 1,
        transactionNo: row.TRNS_UNIQ_NO,
        description: row.DESCRIPTION || row.MESSAGE || '',
        hsnCd: row.HSN_CODE || row.SAC_CODE || '',
        amount: Number(row.CREDITED_TOTAL_AMT || row.FINAL_AMT || row.CREDIT_AMT || 0),
        claimAmount: Number(row.CREDITED_TOTAL_AMT || row.CLAIM_AMT || 0),
        tdsAmount: Number(row.TDS_AMT || 0),
        creditAmount: Number(row.CREDITED_TOTAL_AMT || row.FINAL_AMT || row.CREDIT_AMT || 0)
      }));

      await ClaimCreditNoteItem.bulkCreate(itemsToCreate, { transaction: t });

      await t.commit();
      return true;
    } catch (error) {
      if (t) await t.rollback();
      logger.error(`[CreditNoteSyncService] Error processing claim ${claimNumber}:`, error);
      return false;
    }
  }
}

export const creditNoteSyncService = new CreditNoteSyncService();
